/**
 @file sys_usw_nexthop_misc.c

 @date 2009-11-25

 @version v2.0

 The file contains all non-layer2 and non-layer3 nexthop related callback function
*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"
#include "ctc_common.h"
#include "ctc_spool.h"
#include "ctc_linklist.h"
#include "ctc_packet.h"

#include "sys_usw_common.h"
#include "sys_usw_vlan.h"
#include "sys_usw_internal_port.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_l3if.h"
#include "sys_usw_qos_api.h"
#include "sys_usw_register.h"
#include "sys_usw_stats_api.h"
#include "sys_usw_wb_nh.h"
#include "drv_api.h"

/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/

#define SYS_NH_MISC_FLAG_CONFLICT_CHECK(flag) \
    { \
        if (flag & CTC_MISC_NH_L2_EDIT_SWAP_MAC) \
        { \
            if ((flag & ~CTC_MISC_NH_L2_EDIT_SWAP_MAC) > 0) \
            { \
                return CTC_E_INVALID_PARAM; \
            } \
        } \
    }

extern int32
sys_usw_lkup_ttl_index(uint8 lchip, uint8 ttl, uint32* ttl_index);
/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/

/****************************************************************************
 *
* Function
*
*****************************************************************************/

STATIC int32
_sys_usw_nh_misc_map_vlan_tag_op_translate(uint8 lchip, uint8 op_in, uint8* op_out, uint8* mode_out)
{
    if (CTC_VLAN_TAG_OP_REP_OR_ADD == op_in)
    {
        *mode_out = 1;
    }
    else
    {
        *mode_out = 0;
    }

    switch (op_in)
    {
    case CTC_VLAN_TAG_OP_NONE:
    case CTC_VLAN_TAG_OP_VALID:
        *op_out = DRV_ENUM(DRV_VTAGACTIONTYPE_NONE);
        break;
    case CTC_VLAN_TAG_OP_REP:
    case CTC_VLAN_TAG_OP_REP_OR_ADD:
        *op_out = DRV_ENUM(DRV_VTAGACTIONTYPE_MODIFY);
        break;
    case CTC_VLAN_TAG_OP_ADD:
        *op_out = DRV_ENUM(DRV_VTAGACTIONTYPE_ADD);
        break;
    case CTC_VLAN_TAG_OP_DEL:
        *op_out = DRV_ENUM(DRV_VTAGACTIONTYPE_DELETE);
        break;
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_misc_encoding_vlan_profile(uint8 lchip, ctc_misc_nh_flex_edit_param_t* p_para, DsOfEditVlanActionProfile_m* p_ds)
{

    uint8 tag_action = 0;
    uint8 tag_mode = 0;

    SetDsOfEditVlanActionProfile(V, cCfiAction_f, p_ds, 0);
    SetDsOfEditVlanActionProfile(V, cCosAction_f, p_ds,  p_para->ccos_sl);
    _sys_usw_nh_misc_map_vlan_tag_op_translate(lchip, p_para->ctag_op, &tag_action, &tag_mode);
    SetDsOfEditVlanActionProfile(V, cTagAction_f, p_ds,  tag_action);
    SetDsOfEditVlanActionProfile(V, cTagModifyMode_f , p_ds, tag_mode);
    SetDsOfEditVlanActionProfile(V, cVlanIdAction_f , p_ds,  p_para->cvid_sl);

    SetDsOfEditVlanActionProfile(V, sCfiAction_f, p_ds,  0);
    SetDsOfEditVlanActionProfile(V, sCosAction_f, p_ds, p_para->scos_sl);
    _sys_usw_nh_misc_map_vlan_tag_op_translate(lchip, p_para->stag_op, &tag_action, &tag_mode);
    SetDsOfEditVlanActionProfile(V, sTagAction_f, p_ds,  tag_action);
    SetDsOfEditVlanActionProfile(V, sTagModifyMode_f , p_ds, tag_mode);
    SetDsOfEditVlanActionProfile(V, sVlanIdAction_f , p_ds, p_para->svid_sl);

    if ((CTC_VLAN_TAG_OP_ADD == p_para->ctag_op) && (CTC_VLAN_TAG_OP_ADD == p_para->stag_op))
    {
        SetDsOfEditVlanActionProfile(V, cTagAddMode_f, p_ds,  1);  /*add cvlan before raw packet vlan*/
    }
    else
    {
        SetDsOfEditVlanActionProfile(V, cTagAddMode_f, p_ds,  0);
    }

    SetDsOfEditVlanActionProfile(V, sVlanTpidIndexEn_f, p_ds, p_para->new_stpid_en);
    SetDsOfEditVlanActionProfile(V, sVlanTpidIndex_f, p_ds, p_para->new_stpid_idx);

    return CTC_E_NONE;

}

/**
 @brief Callback function of create unicast bridge nexthop

 @param[in,out] p_com_nh_para, parameters used to create bridge nexthop,
                writeback dsfwd offset array to this param

 @param[out] p_com_db, pointer used to store nexthop data

 @return CTC_E_XXX
 */
int32
sys_usw_nh_create_special_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para, sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_special_t* p_nh_para;
    sys_nh_info_special_t* p_nhdb;
    int32 ret = CTC_E_NONE;


    sys_nh_param_dsfwd_t dsfwd_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* 1. sanity check & init */
    p_nh_para = (sys_nh_param_special_t*)p_com_nh_para;
    p_nhdb = (sys_nh_info_special_t*)p_com_db;
    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));

    switch (p_nh_para->hdr.nh_param_type)
    {
    case SYS_NH_TYPE_UNROV:
    case SYS_NH_TYPE_DROP:
        dsfwd_param.drop_pkt = TRUE;
        break;

    case SYS_NH_TYPE_TOCPU:
        dsfwd_param.is_lcpu = TRUE;
        break;

    default:
        CTC_ERROR_RETURN(CTC_E_INVALID_PARAM);
    }

    p_nhdb->hdr.nh_entry_type =  \
        (p_nhdb->hdr.nh_entry_type == SYS_NH_TYPE_NULL) ? (p_nh_para->hdr.nh_param_type) : p_nhdb->hdr.nh_entry_type;

    sys_usw_get_gchip_id(lchip, &dsfwd_param.dest_chipid);
    dsfwd_param.is_mcast = FALSE;
    dsfwd_param.is_egress_edit =  CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
    dsfwd_param.is_6w = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_DSFWD_IS_6W)?1:0;
    if ((!CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
        && (!CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1)))
    {
        dsfwd_param.is_6w = 1;
    }

    if(SYS_NH_TYPE_TOCPU == p_nh_para->hdr.nh_param_type)
    {
        dsfwd_param.dsnh_offset = CTC_PKT_CPU_REASON_BUILD_NHPTR(CTC_PKT_CPU_REASON_FWD_CPU, 0);
        p_nhdb->hdr.dsnh_offset =  dsfwd_param.dsnh_offset;
    }

    if (p_nh_para->hdr.have_dsfwd)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, 0));
    }

    if (DRV_FROM_AT(lchip) && p_nh_para->hdr.have_dsfwd1)
    {
        ret = (_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, 1));
        if (ret)
        {
            _sys_usw_nh_remove_dsfwd(lchip, p_com_db);
        }
    }

    return ret;
}

int32
sys_usw_nh_delete_special_cb(uint8 lchip, sys_nh_info_com_t* p_data, sys_nh_param_com_t* p_com_nh_para)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    _sys_usw_nh_remove_dsfwd(lchip, p_data);
    return CTC_E_NONE;
}

int32
sys_usw_nh_create_iloop_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                 sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_iloop_t* p_nh_para;
    sys_nh_info_special_t* p_nhdb;
    uint8  gchip = 0;
    sys_nh_param_dsfwd_t dsfwd_param;
    uint16 lport = 0;
    uint8 xgpon_en = 0;
    int32 ret = CTC_E_NONE;


    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* 1. sanity check & init */
    CTC_PTR_VALID_CHECK(p_com_nh_para);
    CTC_PTR_VALID_CHECK(p_com_db);
    p_nh_para = (sys_nh_param_iloop_t*)p_com_nh_para;
    CTC_PTR_VALID_CHECK(p_nh_para->p_iloop_param);
    if (p_nh_para->p_iloop_param->inner_packet_type_valid)
    {
        CTC_MAX_VALUE_CHECK(p_nh_para->p_iloop_param->inner_packet_type, CTC_PARSER_PKT_TYPE_RESERVED);
        if(DRV_FROM_AT(lchip)
            &&(p_nh_para->p_iloop_param->inner_packet_type>=CTC_PARSER_PKT_TYPE_IPV6)
            &&(p_nh_para->p_iloop_param->inner_packet_type<=CTC_PARSER_PKT_TYPE_FLEXIBLE))
            {
            return CTC_E_INVALID_PARAM;
            }
    }
    if (p_nh_para->p_iloop_param->words_removed_from_hdr > MCHIP_CAP(SYS_CAP_NH_ILOOP_MAX_REMOVE_WORDS))
    {
        return CTC_E_INVALID_PARAM;
    }

    sys_usw_global_get_xgpon_en(lchip, &xgpon_en);

    lport = CTC_MAP_GPORT_TO_LPORT(p_nh_para->p_iloop_param->lpbk_lport);

    p_nhdb = (sys_nh_info_special_t*)p_com_db;
    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));

    p_nhdb->hdr.nh_entry_type = (p_nh_para->hdr.nh_param_type);
    if (DRV_FROM_AT(lchip))
    {
        uint32 pp_id = 0;
        sys_usw_dmps_port_info_t dmps_port_info = {0};

        dmps_port_info.gport = p_nh_para->p_iloop_param->lpbk_lport;
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PP_ID, &pp_id));
        dsfwd_param.dest_id = SYS_RSV_PORT_ILOOP_ID-pp_id;
        if (dsfwd_param.dest_id <= SYS_RSV_PORT_SPINE_LEAF_PORT)
        {
            dsfwd_param.dest_id -= 1;
        }
    }
    else
    {
        dsfwd_param.dest_id = (lport%2?SYS_RSV_PORT_ILOOP1_ID:SYS_RSV_PORT_ILOOP_ID);
    }
    dsfwd_param.dsnh_offset = SYS_NH_ENCODE_ILOOP_DSNH(
            lport,
            (p_nh_para->p_iloop_param->logic_port ? \
             1 : 0), p_nh_para->p_iloop_param->customerid_valid,
            p_nh_para->p_iloop_param->words_removed_from_hdr,
            xgpon_en?0:1);
    sys_usw_get_gchip_id(lchip, &gchip);
    p_nhdb->dest_gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, dsfwd_param.dest_id);

    if (p_nh_para->p_iloop_param->customerid_valid)
    {
        dsfwd_param.nexthop_ext = 1;
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
    }

    if(p_nh_para->p_iloop_param->inner_packet_type_valid)
    {
        CTC_BIT_SET(dsfwd_param.dsnh_offset, 11);
        if (DRV_FROM_AT(lchip))
        {
            uint8 pkt_type = (CTC_PARSER_PKT_TYPE_RESERVED == p_nh_para->p_iloop_param->inner_packet_type)?
                            3:p_nh_para->p_iloop_param->inner_packet_type;
            dsfwd_param.dsnh_offset &= ~(0x3000);
            dsfwd_param.dsnh_offset |= ((pkt_type& 0x3) << 12);
        }
        else
        {
            dsfwd_param.dsnh_offset &= ~(0x7000);
            dsfwd_param.dsnh_offset |= ((p_nh_para->p_iloop_param->inner_packet_type& 0x7) << 12);
        }
    }

    /*Build DsFwd Table*/
    p_nhdb->hdr.dsnh_offset = dsfwd_param.dsnh_offset;
    dsfwd_param.is_6w = 1;
    dsfwd_param.dest_chipid = gchip;
    dsfwd_param.is_mcast = FALSE;
    dsfwd_param.is_egress_edit = 1;

    /*Write table*/
    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, 0));
    if (DRV_FROM_AT(lchip))
    {
        ret = (_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, 1));
        if (ret)
        {
            _sys_usw_nh_remove_dsfwd(lchip, p_com_db);
        }
    }


    return ret;
}

int32
sys_usw_nh_delete_iloop_cb(uint8 lchip, sys_nh_info_com_t* p_data, sys_nh_param_com_t* p_com_nh_para)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_EQUAL_CHECK(SYS_NH_TYPE_ILOOP, p_data->hdr.nh_entry_type);
   _sys_usw_nh_remove_dsfwd(lchip, p_data);
    return CTC_E_NONE;
}

int32
sys_usw_nh_update_iloop_cb(uint8 lchip, sys_nh_info_com_t* p_iloop_info, sys_nh_param_com_t* p_iloop_param)
{

    return CTC_E_NONE;
}

int32
sys_usw_nh_create_rspan_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                 sys_nh_info_com_t* p_com_db)
{

    sys_nh_param_rspan_t* p_nh_para;
    sys_nh_param_dsnh_t dsnh_param;
    ctc_vlan_egress_edit_info_t  vlan_egress_edit_info;
    sys_nh_info_rspan_t* p_nhdb = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    /* 1. sanity check & init */
    p_nh_para = (sys_nh_param_rspan_t*)p_com_nh_para;
    p_nhdb = (sys_nh_info_rspan_t*)p_com_db;

    CTC_PTR_VALID_CHECK(p_nh_para->p_rspan_param);
    CTC_VLAN_RANGE_CHECK(p_nh_para->p_rspan_param->rspan_vid);

    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));
    sal_memset(&vlan_egress_edit_info, 0, sizeof(ctc_vlan_egress_edit_info_t));
    vlan_egress_edit_info.output_svid = p_nh_para->p_rspan_param->rspan_vid;

    dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_RSPAN;
    dsnh_param.p_vlan_info = &vlan_egress_edit_info;
    dsnh_param.dsnh_offset = p_nh_para->dsnh_offset;
    dsnh_param.dest_vlan_ptr = p_nh_para->p_rspan_param->rspan_vid;

    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_RSPAN;

    /*Only used for compatible GG Ingress Edit Mode */
    dsnh_param.dsnh_offset = SYS_DSNH_INDEX_FOR_REMOTE_MIRROR;
    CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));

    dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
    CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));

    return CTC_E_NONE;
}

int32
sys_usw_nh_delete_rspan_cb(uint8 lchip, sys_nh_info_com_t* p_com_db, sys_nh_param_com_t* p_com_nh_para)
{
    return CTC_E_NONE;
}


 /* if vlan edit in bucket equals */
STATIC bool
_sys_usw_nh_misc_l2edit_compare_vlan_edit(sys_dsl2edit_vlan_edit_t* pv0,
                                          sys_dsl2edit_vlan_edit_t* pv1)
{
    if (!pv0 || !pv1)
    {
        return FALSE;
    }

    if (!sal_memcmp(pv0, pv1, sizeof(DsOfEditVlanActionProfile_m)))
    {
        return TRUE;
    }

    return FALSE;
}

int32
_sys_usw_nh_misc_vlan_edit_spool_alloc_index(sys_dsl2edit_vlan_edit_t* p_edit, void* user_data)
{
    uint8 lchip = *(uint8*)user_data;
    uint32 profile_id = 0;
    int32 ret = 0;

    if(p_edit->profile_id)
    {
        ret = sys_usw_nh_offset_alloc_from_position(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_VLAN_PROFILE, 1, p_edit->profile_id);
        profile_id = p_edit->profile_id;
    }
    else
    {
        ret = sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_VLAN_PROFILE, 1, &profile_id);

    }

    if(0 == ret)
    {
        p_edit->profile_id = profile_id;
    }

    return ret;
}

int32
_sys_usw_nh_misc_vlan_edit_spool_free_index(sys_dsl2edit_vlan_edit_t* p_edit, void* user_data)
{
    uint8 lchip = *(uint8*)user_data;
    int32 ret = 0;

    CTC_PTR_VALID_CHECK(p_edit);

    ret = sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_VLAN_PROFILE, 1, p_edit->profile_id);

    return ret;
}
STATIC uint32
_sys_usw_nh_misc_l2edit_make_vlan_edit(sys_dsl2edit_vlan_edit_t* pv)
{

    uint8  * k = NULL;
    k    = (uint8 *) pv;

    return ctc_hash_caculate(sizeof(DsOfEditVlanActionProfile_m), k);
}

/* pv_out can be NULL.*/
STATIC int32
_sys_usw_nh_misc_l2edit_add_vlan_edit_spool(uint8 lchip, sys_dsl2edit_vlan_edit_t* pv,
                                             sys_dsl2edit_vlan_edit_t** pv_out)
{
    sys_dsl2edit_vlan_edit_t* pv_get = NULL; /* get from share pool*/
    int32                 ret      = 0;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];

    if(!p_nh_master->p_l2edit_vprof)
    {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
			return CTC_E_NO_MEMORY;

    }
    /* -- set vlan edit ptr -- */
    ret = ctc_spool_add(p_nh_master->p_l2edit_vprof, pv, NULL, &pv_get);
    if (ret < 0)
    {
        ret = CTC_E_NO_MEMORY;
        return ret;
    }

    if (pv_out)
    {
        *pv_out = pv_get;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_misc_l2edit_remove_vlan_edit_spool(uint8 lchip,  sys_dsl2edit_vlan_edit_t* pv)

{
    int32                 ret = 0;
    sys_dsl2edit_vlan_edit_t* pv_lkup;
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];

    if(NULL == p_nh_master->p_l2edit_vprof)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }

    ret = ctc_spool_remove(p_nh_master->p_l2edit_vprof, pv, &pv_lkup);
    if (ret < 0)
    {
        return CTC_E_NOT_EXIST;
    }

    return CTC_E_NONE;
}
STATIC int32
_sys_usw_nh_misc_build_outer_l2_for_mpls(uint8 lchip, uint32* l2_edit_ptr, uint8 is_add)/*TMM*/
{
    uint32 cmd = 0;
    DsL2EditRwEth1X_m dsl2edit;
    ds0_t ds;
    sys_usw_nh_master_t* p_usw_nh_master = g_usw_nh_master[lchip];
    uint32 tbl_id = 0;
    uint32 offset = 0;

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    if (is_add)
    {
        if (0 == p_usw_nh_master->outer_l2_ptr_ref)
        {
            CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, 1, &p_usw_nh_master->outer_l2_ptr));
            sal_memset(&dsl2edit, 0, sizeof(dsl2edit));
            sal_memset(&ds, 0, sizeof(ds));

            tbl_id = (p_usw_nh_master->outer_l2_ptr >= MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM))?DsL3Edit6W3rd_t:DsL2Edit6WOuter_t;
            offset = (p_usw_nh_master->outer_l2_ptr >= MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM))?(p_usw_nh_master->outer_l2_ptr - MCHIP_CAP(SYS_CAP_NH_OUTER_L2_EDIT_NUM)):
                p_usw_nh_master->outer_l2_ptr;

            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, offset / 2, cmd, &ds));
            SetDsL2EditRwEth1X(V, dsType_f,                &dsl2edit,  SYS_NH_DS_TYPE_L2EDIT);
            SetDsL2EditRwEth1X(V, l2EditType_f,                &dsl2edit,  DRV_ENUM(DRV_L2EDITTYPE_RWETH1X));
            SetDsL2EditRwEth1X(V, etherTypeRewriteEn_f,                &dsl2edit,  1);
            if (p_usw_nh_master->outer_l2_ptr % 2 == 0)
            {
                sal_memcpy((uint8*)&ds, &dsl2edit, DRV_TABLE_ENTRY_SIZE(lchip, DsL2Edit6WOuter_t) / 2);
            }
            else
            {
                sal_memcpy((uint8*)&ds + DRV_TABLE_ENTRY_SIZE(lchip, DsL2Edit6WOuter_t) / 2, &dsl2edit, DRV_TABLE_ENTRY_SIZE(lchip, DsL2Edit6WOuter_t) / 2);
            }
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, offset/2, cmd, &ds));

        }
        p_usw_nh_master->outer_l2_ptr_ref++;
        *l2_edit_ptr = p_usw_nh_master->outer_l2_ptr;
    }
    else
    {
        if ((*l2_edit_ptr == p_usw_nh_master->outer_l2_ptr) && (p_usw_nh_master->outer_l2_ptr_ref > 0))
        {
            p_usw_nh_master->outer_l2_ptr_ref--;
        }
        if(0 == p_usw_nh_master->outer_l2_ptr_ref)
        {
            sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, 1, *l2_edit_ptr);
            p_usw_nh_master->outer_l2_ptr = 0;
        }
    }
    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_misc_build_l2_edit(uint8 lchip, sys_nh_param_misc_t* p_nh_misc,
                                    sys_nh_info_misc_t* p_nhdb)
{
    int32 ret = CTC_E_NONE;
    uint8 misc_type = 0;
    ctc_misc_nh_param_t* p_edit_param = p_nh_misc->p_misc_param;
    ctc_misc_nh_flex_edit_param_t  *p_flex_edit         = NULL;
    ctc_misc_nh_over_l2_edit_param_t  *p_over_l2edit    = NULL;

    uint8 entry_type = 0;
    sys_dsl2edit_of6w_t dsl2edit;
    sys_dsl2edit_eth_t ds_eth_l2_edit;
    void *p_dsl2edit = NULL;

    uint32 offset = 0;

    sal_memset(&dsl2edit, 0, sizeof(dsl2edit));
    sal_memset(&ds_eth_l2_edit, 0, sizeof(sys_dsl2edit_eth_t));
    misc_type = p_edit_param->type;
    if((CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == misc_type) || (CTC_MISC_NH_TYPE_OVER_L2 == misc_type))
    {
        p_over_l2edit = &p_edit_param->misc_param.over_l2edit;
    }
    else if(CTC_MISC_NH_TYPE_FLEX_EDIT_HDR == misc_type)
    {
        p_flex_edit = &p_edit_param->misc_param.flex_edit;
    }

    if(p_flex_edit)
    {
        if (CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_SWAP_MACDA))
        {
            if (!DRV_FROM_TMM(lchip) && (CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_VLAN_TAG) && (0 == p_flex_edit->user_vlanptr)))
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
                return CTC_E_NOT_SUPPORT;
            }

            dsl2edit.p_flex_edit = p_flex_edit;
            entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_SWAP;
            p_dsl2edit = &dsl2edit;
        }

        if ((!CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IP_HDR)
            && CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_DECREASE_TTL) && !DRV_FROM_TMM(lchip))
            || (!CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_MACSA) && (0 != p_nh_misc->hdr.xgpon_hybrid)))
        {
            ds_eth_l2_edit.ds_type = SYS_NH_DS_TYPE_L2EDIT;
            ds_eth_l2_edit.l2_rewrite_type = g_usw_nh_master[lchip]->rewrite_type[SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W];
            ds_eth_l2_edit.output_vid = p_flex_edit->new_svid;
            ds_eth_l2_edit.output_cvid = p_flex_edit->new_cvid;
            ds_eth_l2_edit.is_8w = 1;
            sal_memcpy(ds_eth_l2_edit.mac_da, p_flex_edit->mac_da, sizeof(mac_addr_t));
            sal_memcpy(ds_eth_l2_edit.mac_sa, p_flex_edit->mac_sa, sizeof(mac_addr_t));
            ds_eth_l2_edit.update_mac_sa = 1;
            ds_eth_l2_edit.ether_type    = p_flex_edit->ether_type;
            entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W;
            if (0 != p_nh_misc->hdr.xgpon_hybrid)
            {
                ds_eth_l2_edit.is_8w = 0;
                ds_eth_l2_edit.l2_rewrite_type = g_usw_nh_master[lchip]->rewrite_type[SYS_NH_ENTRY_TYPE_L2EDIT_INNER_SWAP];
                entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_SWAP;
            }
            p_dsl2edit = &ds_eth_l2_edit;
        }
        else if(DRV_FROM_TMM(lchip) || !(CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_SWAP_MACDA)))
        {
            sys_dsl2edit_vlan_edit_t vlan_edit;
            sys_dsl2edit_vlan_edit_t *p_edit_out;

            sal_memset(&vlan_edit, 0, sizeof(sys_dsl2edit_vlan_edit_t));
            dsl2edit.vlan_profile_id = 0;
            dsl2edit.p_flex_edit = p_flex_edit;
            if (CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_VLAN_TAG) && (0 == p_nh_misc->hdr.xgpon_hybrid))
            {
                CTC_ERROR_RETURN(_sys_usw_nh_misc_encoding_vlan_profile(lchip, p_flex_edit, &(vlan_edit.data)));
                CTC_ERROR_RETURN(_sys_usw_nh_misc_l2edit_add_vlan_edit_spool(lchip, &vlan_edit, &p_edit_out));
                CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip,  SYS_NH_ENTRY_TYPE_L2EDIT_VLAN_PROFILE,
                    p_edit_out->profile_id, &(vlan_edit.data)));
                dsl2edit.vlan_profile_id = p_edit_out->profile_id;
                p_nhdb->vlan_profile_id = p_edit_out->profile_id;
            }
            entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_OF_6W;
            p_dsl2edit = &dsl2edit;
        }
    }
    else if (p_over_l2edit)
    {
        if (p_over_l2edit->raw_data_len)
        {
            sys_dsl3edit_raw_t l3edit_raw;
            uint32 data_tmp[SYS_L3EDIT_RAW_LEN_MAX] = {0};
            mac_addr_t mac = {0};
            sal_memset(&l3edit_raw, 0, sizeof(l3edit_raw));
            entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_ADD_RAW;
            l3edit_raw.data_len = p_over_l2edit->raw_data_len;
            sal_memcpy((uint8*)data_tmp, p_over_l2edit->raw_data, p_over_l2edit->raw_data_len);
            sys_usw_swap32(data_tmp, SYS_L3EDIT_RAW_LEN_MAX, FALSE);
            sys_usw_dword_reverse_copy(l3edit_raw.data, data_tmp, SYS_L3EDIT_RAW_LEN_MAX);
            CTC_ERROR_RETURN(sys_usw_nh_add_l3edit_tunnel(lchip, &l3edit_raw, entry_type, &offset));
            CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
            p_nhdb->l3edit_entry_type = entry_type;
            p_nhdb->dsl3edit_offset = offset;

            /*inner l2*/
            entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W + SYS_NH_TYPE_STEP_TO_INNER;

            if ((0 == sal_memcmp(p_over_l2edit->mac_da, mac, 6)) && (0 == sal_memcmp(p_over_l2edit->mac_sa, mac, 6)))
            {
                return CTC_E_NONE;/*only raw data, no l2 edit*/
            }
        }
        else
        {
            /*outer l2*/
            entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W;
        }
        ds_eth_l2_edit.ds_type = SYS_NH_DS_TYPE_L2EDIT;
        ds_eth_l2_edit.l2_rewrite_type = g_usw_nh_master[lchip]->rewrite_type[SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W];
        ds_eth_l2_edit.output_vid = p_over_l2edit->vlan_id;
        ds_eth_l2_edit.output_cvid = p_over_l2edit->cvlan_id;
        ds_eth_l2_edit.is_8w = 1;
        sal_memcpy(ds_eth_l2_edit.mac_da, p_over_l2edit->mac_da, sizeof(mac_addr_t));
        sal_memcpy(ds_eth_l2_edit.mac_sa, p_over_l2edit->mac_sa, sizeof(mac_addr_t));
        ds_eth_l2_edit.update_mac_sa = 1;
        ds_eth_l2_edit.ether_type    = p_over_l2edit->ether_type;
        if (CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == misc_type)
        {
            ds_eth_l2_edit.is_span_ext_hdr = 1;
        }
        p_dsl2edit = &ds_eth_l2_edit;
    }
    else if (CTC_MISC_NH_TYPE_FP_EDIT == misc_type)
    {   /*for xedit, dsnexthop->dsedit->dsXedit, dsedit do nothing*/
        ds_eth_l2_edit.ds_type = SYS_NH_DS_TYPE_L2EDIT;
        ds_eth_l2_edit.l2_rewrite_type = g_usw_nh_master[lchip]->rewrite_type[SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W_RW];
        ds_eth_l2_edit.xeditptr = p_nh_misc->xeditptr;
        entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W_RW;
        p_dsl2edit = &ds_eth_l2_edit;
    }
    if (p_dsl2edit)
    {
        CTC_ERROR_GOTO(sys_usw_nh_add_l2edit(lchip, p_dsl2edit, entry_type, &offset), ret, error0);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
        p_nhdb->l2edit_entry_type = entry_type;
        p_nhdb->dsl2edit_offset = offset;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "DsL2Edit, offset = %d\n",  offset);
    }


    return CTC_E_NONE;
error0:
    if(CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT))
    {
        sys_usw_nh_offset_free(lchip, p_nhdb->l3edit_entry_type, 1, p_nhdb->dsl3edit_offset);
    }
    return ret;

}

STATIC int32
_sys_usw_nh_misc_build_l3_edit(uint8 lchip, ctc_misc_nh_param_t* p_edit_param,
                                    sys_nh_info_misc_t* p_nhdb)
{
    ctc_misc_nh_flex_edit_param_t  *p_flex_edit = &p_edit_param->misc_param.flex_edit;
    uint32 offset = 0;
    uint8 entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_OF_6W + SYS_NH_TYPE_STEP_TO_INNER;

    if (!CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_IPV4)
          || (p_flex_edit->packet_type == CTC_MISC_NH_PACKET_TYPE_ARP
               && CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_ARP_HDR)))
    {
        entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_OF_12W + SYS_NH_TYPE_STEP_TO_INNER;
    }
    CTC_ERROR_RETURN(sys_usw_nh_add_l3edit_tunnel(lchip, p_flex_edit, entry_type, &offset));
    p_nhdb->dsl3edit_offset = offset;
    CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
    p_nhdb->l3edit_entry_type = entry_type;

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_misc_encode_mpls_edit(uint8 lchip, ctc_mpls_nh_label_param_t* p_label, sys_dsmpls_t*  p_dsmpls)
{
    uint32 ttl_index = 0;

    p_dsmpls->l3_rewrite_type = DRV_FROM_TMM(lchip)? DRV_ENUM(DRV_L3EDITTYPE_MPLS1X) : SYS_NH_L3EDIT_TYPE_MPLS_4W;
    p_dsmpls->ds_type = SYS_NH_DS_TYPE_L3EDIT;
    p_dsmpls->oam_en = 0;

    if (CTC_FLAG_ISSET(p_label->lable_flag, CTC_MPLS_NH_LABEL_MAP_TTL))
    {
        p_dsmpls->map_ttl = 1;
        p_dsmpls->map_ttl_mode = 1;     /* only for lsp label */
    }

    if (CTC_FLAG_ISSET(p_label->lable_flag, CTC_MPLS_NH_LABEL_IS_MCAST))
    {
        p_dsmpls->mcast_label = 1;
    }

    CTC_ERROR_RETURN(sys_usw_lkup_ttl_index(lchip, p_label->ttl, &ttl_index));
    p_dsmpls->ttl_index = ttl_index;
    p_dsmpls->label  = (p_label->label & 0xFFFFF);   /*label*/

    switch (p_label->exp_type)
    {
        case CTC_NH_EXP_SELECT_ASSIGN:   /* user cfg exp  */
            p_dsmpls->derive_exp  = 0;
            p_dsmpls->exp = p_label->exp & 0x7;
            break;

        case CTC_NH_EXP_SELECT_MAP:  /*mapped exp */
            p_dsmpls->derive_exp = 1;
            p_dsmpls->exp = SYS_NH_MPLS_LABEL_EXP_SELECT_MAP;
            p_dsmpls->mpls_domain = p_label->exp_domain;
            break;

        case CTC_NH_EXP_SELECT_PACKET:   /*input packet exp  */

            p_dsmpls->derive_exp = 1;
            p_dsmpls->exp = SYS_NH_MPLS_LABEL_EXP_SELECT_PACKET;
            break;

        default:
            break;
    }

    p_dsmpls->derive_label = 1;
    p_dsmpls->edit_mode = 1;

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_misc_build_mpls_edit(uint8 lchip, ctc_misc_nh_param_t* p_edit_param,
                                    sys_nh_info_misc_t* p_nhdb)
{
    sys_dsmpls_t dsmpls;
    uint32 offset = 0;
    int32 ret = 0;
    uint8 entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_MPLS;

    /*1. process first label*/
    sal_memset(&dsmpls, 0, sizeof(sys_dsmpls_t));
    _sys_usw_nh_misc_encode_mpls_edit(lchip, &p_edit_param->misc_param.flex_edit.label[0], &dsmpls);
    CTC_ERROR_RETURN(sys_usw_nh_add_l3edit_tunnel(lchip, &dsmpls, entry_type + SYS_NH_TYPE_STEP_TO_INNER, &offset));
    p_nhdb->dsl3edit_offset = offset;
    CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
    p_nhdb->l3edit_entry_type = entry_type + SYS_NH_TYPE_STEP_TO_INNER;
    p_nhdb->label_num = p_edit_param->misc_param.flex_edit.label_num;

    /*2. process second label*/
    if(p_nhdb->label_num  > 1)
    {
        sal_memset(&dsmpls, 0, sizeof(sys_dsmpls_t));
        if (p_nhdb->dsl2edit_offset)
        {
            dsmpls.next_editptr_valid = 1;
            dsmpls.outer_editptr = p_nhdb->dsl2edit_offset;
        }
        _sys_usw_nh_misc_encode_mpls_edit(lchip, &p_edit_param->misc_param.flex_edit.label[1], &dsmpls);
        CTC_ERROR_GOTO(sys_usw_nh_add_l3edit_tunnel(lchip, &dsmpls, entry_type, &offset), ret, error0);
        p_nhdb->next_l3edit_entry_type = entry_type;
        p_nhdb->next_l3edit_offset = offset;
    }
    return CTC_E_NONE;

error0:
    sys_usw_nh_remove_l3edit_tunnel(lchip, entry_type+SYS_NH_TYPE_STEP_TO_INNER, p_nhdb->dsl3edit_offset);

    CTC_UNSET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
    p_nhdb->next_l3edit_offset = 0;
    return ret;
}

STATIC int32
_sys_usw_nh_misc_map_dsnh_vlan_info(uint8 lchip, ctc_misc_nh_flex_edit_param_t* p_flex_edit,
                                             ctc_vlan_egress_edit_info_t* p_vlan_info)
{

    CTC_PTR_VALID_CHECK(p_flex_edit);
    CTC_PTR_VALID_CHECK(p_vlan_info);

    /* 1. svlan info map */
    switch (p_flex_edit->stag_op)
    {
    case CTC_VLAN_TAG_OP_NONE:
    case CTC_VLAN_TAG_OP_VALID:
        p_vlan_info->svlan_edit_type = CTC_VLAN_EGRESS_EDIT_NONE;
        break;

    case CTC_VLAN_TAG_OP_REP_OR_ADD:
        p_vlan_info->svlan_edit_type = CTC_VLAN_EGRESS_EDIT_REPLACE_VLAN;
        break;

    case CTC_VLAN_TAG_OP_REP:
        p_vlan_info->svlan_edit_type = CTC_VLAN_EGRESS_EDIT_REPLACE_VLAN;
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_SVLAN_AWARE);
        break;

    case CTC_VLAN_TAG_OP_ADD:
        p_vlan_info->svlan_edit_type = CTC_VLAN_EGRESS_EDIT_INSERT_VLAN;
        break;

    case CTC_VLAN_TAG_OP_DEL:
        p_vlan_info->svlan_edit_type = CTC_VLAN_EGRESS_EDIT_STRIP_VLAN;
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }

    if (p_flex_edit->svid_sl == CTC_VLAN_TAG_SL_NEW)
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID);
        p_vlan_info->output_svid = p_flex_edit->new_svid;
    }
    else if ((p_flex_edit->svid_sl == CTC_VLAN_TAG_SL_ALTERNATIVE) && (p_flex_edit->cvid_sl == CTC_VLAN_TAG_SL_ALTERNATIVE))
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_VLAN_SWAP_EN);

        if ((p_flex_edit->scos_sl == CTC_VLAN_TAG_SL_ALTERNATIVE) && (p_flex_edit->ccos_sl == CTC_VLAN_TAG_SL_ALTERNATIVE))
        {
            CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_COS_SWAP_EN);
        }
    }
    else if (p_flex_edit->svid_sl != CTC_VLAN_TAG_SL_AS_PARSE)
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_flex_edit->scos_sl == CTC_VLAN_TAG_SL_NEW)
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_REPLACE_SVLAN_COS);
        p_vlan_info->stag_cos = p_flex_edit->new_scos;
    }
    else if (p_flex_edit->scos_sl == CTC_VLAN_TAG_SL_DEFAULT)
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_MAP_SVLAN_COS);
    }
    else if ((p_flex_edit->scos_sl == CTC_VLAN_TAG_SL_ALTERNATIVE) && (!CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_COS_SWAP_EN)))
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_flex_edit->new_stpid_en)
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUTPUT_SVLAN_TPID_VALID);
        p_vlan_info->svlan_tpid_index = p_flex_edit->new_stpid_idx;
    }


    /* 2. cvlan info map */
    switch (p_flex_edit->ctag_op)
    {
    case CTC_VLAN_TAG_OP_NONE:
    case CTC_VLAN_TAG_OP_VALID:
        p_vlan_info->cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_NONE;
        break;

    case CTC_VLAN_TAG_OP_REP_OR_ADD:
        p_vlan_info->cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_REPLACE_VLAN;
        break;

    case CTC_VLAN_TAG_OP_ADD:
        p_vlan_info->cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_INSERT_VLAN;
        break;

    case CTC_VLAN_TAG_OP_DEL:
        p_vlan_info->cvlan_edit_type = CTC_VLAN_EGRESS_EDIT_STRIP_VLAN;
        break;

    default: /* CTC_VLAN_TAG_OP_REP */
        return CTC_E_INVALID_PARAM;
    }

    if (p_flex_edit->cvid_sl == CTC_VLAN_TAG_SL_NEW)
    {
        CTC_SET_FLAG(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_CVID_VALID);
        p_vlan_info->output_cvid = p_flex_edit->new_cvid;
    }
    else if ((p_flex_edit->cvid_sl != CTC_VLAN_TAG_SL_AS_PARSE) && (!CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_VLAN_SWAP_EN)))
    {
        return CTC_E_INVALID_PARAM;
    }

    if ((p_flex_edit->ccos_sl != CTC_VLAN_TAG_SL_AS_PARSE) && (!CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_COS_SWAP_EN)))
    {
        return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_misc_write_dsnh(uint8 lchip, sys_nh_param_misc_t* p_nh_misc ,
                                    sys_nh_info_misc_t* p_nhdb)
{
    uint8 gchip = 0;
    sys_nh_param_dsnh_t dsnh_param;
    uint8 misc_type = 0;
    uint16 dest_vlan_ptr = SYS_DSNH_DESTVLANPTR_SPECIAL;
    sys_l3if_prop_t l3if_prop;
    ctc_vlan_egress_edit_info_t vlan_info;
    uint8 dsnh_type = SYS_NH_PARAM_DSNH_TYPE_OF;
    uint8 index = 0;
    uint32 offset = 0;
    uint8 edit_dsnh = 1;

    ctc_misc_nh_flex_edit_param_t  *p_flex_edit = NULL;
    ctc_misc_nh_over_l2_edit_param_t  *p_over_l2_edit = NULL;
    ctc_misc_nh_fp_edit_param_t *p_fp_edit = NULL;
    ctc_nh_oif_info_t *p_oif = NULL;

    sal_memset(&l3if_prop, 0, sizeof(l3if_prop));
    sal_memset(&vlan_info, 0, sizeof(vlan_info));

    if (!p_nh_misc->p_misc_param)
    {
        return CTC_E_NOT_EXIST;
    }
    edit_dsnh = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW)? 0 : 1;
    misc_type =  p_nh_misc->p_misc_param->type;
    if ((CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == misc_type) || (CTC_MISC_NH_TYPE_OVER_L2 == misc_type))
    {
        p_over_l2_edit = &p_nh_misc->p_misc_param->misc_param.over_l2edit;
        p_nhdb->flag = p_nh_misc->p_misc_param->misc_param.over_l2edit.flag;
    }
    else if(CTC_MISC_NH_TYPE_FLEX_EDIT_HDR == misc_type)
    {
        p_flex_edit = &p_nh_misc->p_misc_param->misc_param.flex_edit;
        p_nhdb->packet_type = p_flex_edit->packet_type;
        p_nhdb->ctag_op = p_flex_edit->ctag_op;
        p_nhdb->cvid_sl = p_flex_edit->cvid_sl;
        p_nhdb->ccos_sl = p_flex_edit->ccos_sl;
        p_nhdb->stag_op = p_flex_edit->stag_op;
        p_nhdb->svid_sl = p_flex_edit->svid_sl;
        p_nhdb->scos_sl = p_flex_edit->scos_sl;
        p_nhdb->flag = p_flex_edit->flag;
    }
    else if(CTC_MISC_NH_TYPE_FP_EDIT == misc_type || CTC_MISC_NH_TYPE_ERSPAN == misc_type)
    {
        p_fp_edit = (ctc_misc_nh_fp_edit_param_t *)&p_nh_misc->p_misc_param->misc_param.fp_edit;
        p_nhdb->flag = p_fp_edit->flag;
    }

    sys_usw_get_gchip_id(lchip, &gchip);

    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));

    if (p_nh_misc->p_misc_param->logic_port)
    {
        dsnh_param.logic_port     = p_nh_misc->p_misc_param->logic_port;
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOGIC_PORT);
        dsnh_param.dvp_tbl_valid = 1;
    }

    dsnh_param.stats_ptr = p_nh_misc->hdr.stats_ptr;
    dsnh_param.cid = p_nh_misc->p_misc_param->cid;
    if(p_flex_edit)
    {
        if (p_flex_edit->is_reflective)
        {
           p_nh_misc->p_misc_param->gport = CTC_MAP_LPORT_TO_GPORT(gchip, 0);
           p_nhdb->is_reflective = p_flex_edit->is_reflective;
           p_nh_misc->hdr.have_dsfwd = 1;
           p_nh_misc->hdr.have_dsfwd1 = 1;
        }

        dest_vlan_ptr = p_flex_edit->user_vlanptr ? p_flex_edit->user_vlanptr : dest_vlan_ptr;
    }

    p_oif = &(p_nh_misc->p_misc_param->oif);
    p_nhdb->gport = p_nh_misc->p_misc_param->is_oif ? p_oif->gport : p_nh_misc->p_misc_param->gport;

    if (DRV_IS_DUET2(lchip))
    {
        if (((dest_vlan_ptr>>10)&0x7) == 4)
        {
            p_nhdb->l3ifid = (dest_vlan_ptr&0x3ff);
        }
    }
    else
    {
        if (dest_vlan_ptr&0x3000)
        {
            p_nhdb->l3ifid = dest_vlan_ptr - MCHIP_CAP(SYS_CAP_L3IF_VLAN_PTR_BASE);
        }
    }

    if (!p_nh_misc->p_misc_param->loop_nhid &&
        p_nh_misc->p_misc_param->is_oif && (!(CTC_IS_CPU_PORT(p_oif->gport) || p_oif->is_l2_port)))
    {
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info_with_port_and_vlan(lchip, p_oif->gport, p_oif->vid, p_oif->cvid, &l3if_prop));
        dest_vlan_ptr = l3if_prop.vlan_ptr;
        p_nhdb->l3ifid = l3if_prop.l3if_id;
    }


    if (p_flex_edit && edit_dsnh)
    {
        if ((p_flex_edit->packet_type == CTC_MISC_NH_PACKET_TYPE_MPLS) && p_flex_edit->flag)
        {
            return CTC_E_NOT_SUPPORT;
        }

        if (p_flex_edit->packet_type == CTC_MISC_NH_PACKET_TYPE_MPLS)
        {
            if (p_flex_edit->label_num > CTC_MPLS_NH_MAX_FLEX_LABEL_NUM)
            {
                return CTC_E_INVALID_PARAM;
            }

            for (index = 0; index < p_flex_edit->label_num; index++)
            {
                SYS_NH_CHECK_MPLS_LABVEL_VALUE(p_flex_edit->label[index].label);
                SYS_NH_CHECK_MPLS_EXP_VALUE(p_flex_edit->label[index].exp);
                SYS_NH_CHECK_MPLS_EXP_TYPE_VALUE(p_flex_edit->label[index].exp_type);
                CTC_MAX_VALUE_CHECK(p_flex_edit->label[index].exp_domain, 15);
            }

            if (DRV_FROM_TMM(lchip))
            {
                CTC_ERROR_RETURN(_sys_usw_nh_misc_build_outer_l2_for_mpls(lchip, &offset, 1));
                p_nhdb->dsl2edit_offset = offset;
            }

            CTC_ERROR_RETURN(_sys_usw_nh_misc_build_mpls_edit(lchip, p_nh_misc->p_misc_param, p_nhdb));
            dsnh_type = SYS_NH_PARAM_DSNH_TYPE_MPLS_PUSH_OP_NONE;
            if (p_flex_edit->label_num > 1)
            {
                dsnh_param.lspedit_ptr = p_nhdb->next_l3edit_offset;
            }
        }
        else
        {
            if(p_nh_misc->p_misc_param->loop_nhid)
            {
                 uint16 lport = 0;
                 uint8 lb_with_ldp = CTC_FLAG_ISSET(p_nh_misc->p_misc_param->flag, CTC_MISC_NH_FLAG_LB_WITH_LOGIC_DST_PORT);
                 sys_nh_info_dsnh_t nhinfo;
                 sal_memset(&nhinfo, 0, sizeof(nhinfo));
                CTC_ERROR_RETURN(sys_usw_nh_add_loopback_l2edit(lchip, p_nh_misc->p_misc_param->loop_nhid, lb_with_ldp, TRUE, &offset));
                p_nhdb->dsl2edit_offset = offset;
                sys_usw_get_gchip_id(lchip, &gchip);
                CTC_ERROR_RETURN(_sys_usw_nh_get_nhinfo(lchip, p_nh_misc->p_misc_param->loop_nhid, &nhinfo));
                sys_usw_internal_port_get_rsv_port(lchip, SYS_INTERNAL_PORT_TYPE_ELOOP, nhinfo.gport, &lport);
                p_nhdb->gport  = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);
                dest_vlan_ptr= MCHIP_CAP(SYS_CAP_L3IF_RSV_L3IF_ID) + MCHIP_CAP(SYS_CAP_L3IF_VLAN_PTR_BASE);
                p_nhdb->is_loop_nh = 1;
                if (lb_with_ldp)
                {
                    CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LB_WITH_LOGIC_DST);
                    dsnh_param.dvp_tbl_valid=1;
                }
            }
            else if(CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_L2_HDR))
            {
                p_nh_misc->hdr.xgpon_hybrid = sys_usw_nh_is_xgpon_hybrid(lchip, p_nh_misc->p_misc_param->logic_port);
                CTC_ERROR_RETURN(_sys_usw_nh_misc_build_l2_edit(lchip, p_nh_misc, p_nhdb));

                if (CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_OP_BRIDGE))
                {
                    CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_MISC_FLEX_PLD_BRIDGE);
                }

                if (CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_VLAN_TAG) && p_nh_misc->hdr.xgpon_hybrid)
                {
                    CTC_ERROR_RETURN(_sys_usw_nh_misc_map_dsnh_vlan_info(lchip, p_flex_edit, &vlan_info));
                    dsnh_param.p_vlan_info = &vlan_info;
                    if (DRV_IS_TSINGMA(lchip))
                    {
                        dsnh_param.tag_disable = 1;
                    }
                }
            }

            if(((p_flex_edit->packet_type != CTC_MISC_NH_PACKET_TYPE_ARP)
                && CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IP_HDR))
                || CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_ARP_HDR))
            {
              CTC_ERROR_RETURN(_sys_usw_nh_misc_build_l3_edit(lchip, p_nh_misc->p_misc_param,p_nhdb));
            }
        }
        dsnh_param.dsnh_type = dsnh_type;
        dsnh_param.dest_vlan_ptr = 	dest_vlan_ptr;
        if (p_nh_misc->hdr.xgpon_hybrid)
        {
           dsnh_param.inner_l2edit_ptr = p_nhdb->dsl2edit_offset;
           dsnh_param.l2edit_ptr = SYS_NH_GEMPORT_MAP(p_nh_misc->p_misc_param->logic_port);
           dsnh_param.pl_op = SYS_NH_OP_ROUTE;
        }
        else
        {
            dsnh_param.l2edit_ptr = p_nhdb->dsl2edit_offset;
            dsnh_param.l3edit_ptr = p_nhdb->dsl3edit_offset;
        }
        dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
        dsnh_param.mtu_no_chk = CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_MTU_CHECK) ? 0 : 1;

        if (!CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IP_HDR)
            && CTC_FLAG_ISSET(p_flex_edit->flag, CTC_MISC_NH_FLEX_EDIT_DECREASE_TTL))
        {
            dsnh_param.pl_op = SYS_NH_OP_ROUTE;
        }

        if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));
        }

    }

    if (CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == misc_type && DRV_FROM_TMM(lchip) && edit_dsnh)
    {
        uint16 len = 0;
        uint16 ts_offset = 0;
        uint8 data[40] = {0};
        ctc_nh_fp_edit_t fp_edit;
        ctc_nh_fp_field_t field_list[5];
        sys_nh_info_dsnh_t fp_info;
        uint16 tmp_l2_offset = 0;
        uint8 zone = DRV_FROM_AT(lchip)? CTC_NH_FP_ZONE_PACKET : CTC_NH_FP_ZONE_INS_DATA;
        ts_offset = 128;
        len = 32;

        /* 1. init flex edit for none psp*/
        sal_memset(&fp_edit, 0, sizeof(ctc_nh_fp_edit_t));
        sal_memset(&field_list, 0, sizeof(field_list));

        fp_edit.p_field_list = field_list;
        fp_edit.edit_type = CTC_NH_FP_EDIT_INS;
        fp_edit.offset = 0;
        fp_edit.offset_type = CTC_PKT_OFFSET_L2;

        sal_memcpy(data, p_over_l2_edit->mac_da, sizeof(mac_addr_t));
        sal_memcpy(data + 6, p_over_l2_edit->mac_sa, sizeof(mac_addr_t));

        tmp_l2_offset = 12;
        if (p_over_l2_edit->vlan_id)
        {
            data[tmp_l2_offset++] = 0x81;
            data[tmp_l2_offset++] = 0x00;
            data[tmp_l2_offset++] = (p_over_l2_edit->vlan_id >> 8);
            data[tmp_l2_offset++] = (p_over_l2_edit->vlan_id & 0xFF);

            len +=  4;
            ts_offset += 32;
        }

        if (p_over_l2_edit->cvlan_id)
        {
            data[tmp_l2_offset++] = 0x81;
            data[tmp_l2_offset++] = 0x00;
            data[tmp_l2_offset++] = (p_over_l2_edit->cvlan_id >> 8);
            data[tmp_l2_offset++] = (p_over_l2_edit->cvlan_id & 0xFF);
            len +=  4;
            ts_offset += 32;
        }

        data[tmp_l2_offset++] = (p_over_l2_edit->ether_type >> 8);
        data[tmp_l2_offset++] = (p_over_l2_edit->ether_type & 0xFF);

        fp_edit.data = data;
        fp_edit.len = len;

        fp_edit.field_cnt = 5;

        field_list[0].offset = ts_offset;
        field_list[0].len = 32;
        field_list[0].data.type = CTC_NH_FP_DATA_IGS_TS_HIGH;
        field_list[0].data.len = 32;
        field_list[0].data.shift = 0;
        field_list[0].zone = zone;

        field_list[1].offset = ts_offset + 32*1;
        field_list[1].len = 32;
        field_list[1].data.type = CTC_NH_FP_DATA_IGS_TS_LOW;
        field_list[1].data.len = 32;
        field_list[1].data.shift = 0;
        field_list[1].zone = zone;

        field_list[2].offset = ts_offset + 32*2;
        field_list[2].len = 32;
        field_list[2].data.type = CTC_NH_FP_DATA_TS_HIGH;
        field_list[2].data.len = 32;
        field_list[2].data.shift = 0;
        field_list[2].zone = zone;

        field_list[3].offset = ts_offset + 32*3;
        field_list[3].len = 32;
        field_list[3].data.type = CTC_NH_FP_DATA_TS_LOW;
        field_list[3].data.len = 32;
        field_list[3].data.shift = 0;
        field_list[3].zone = zone;

        field_list[4].offset = ts_offset - 16;
        field_list[4].len = 16;
        field_list[4].data.type = CTC_NH_FP_DATA_SPAN_ID;
        field_list[4].data.len = 16;
        field_list[4].data.shift = 0;
        field_list[4].zone = zone;
        if (DRV_FROM_AT(lchip))
        {
            CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_REP_SEL_VALID);
            fp_edit.replace_sel = 1;
        }

        CTC_ERROR_RETURN(MCHIP_NH(lchip)->add_fp(lchip, &fp_edit, 1));
        p_nhdb->dsl3edit_offset = fp_edit.fp_id;
        p_nhdb->l3edit_entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_FP;


        sal_memset(&fp_info, 0, sizeof(sys_nh_info_dsnh_t));
        CTC_ERROR_RETURN(MCHIP_NH(lchip)->get_fp_info(lchip, fp_edit.fp_id, &fp_info));

        dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_OF;
        dsnh_param.dest_vlan_ptr = dest_vlan_ptr;
        dsnh_param.l3edit_ptr = fp_info.l3_edit_ptr;
        dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
        dsnh_param.span_id = p_over_l2_edit->flow_id;
        if (p_over_l2_edit->flag & CTC_MISC_NH_OVER_L2_EDIT_VLAN_EDIT)
        {
            dsnh_param.p_vlan_info = &p_over_l2_edit->vlan_info;
            p_nhdb->svlan_edit_type = dsnh_param.p_vlan_info->svlan_edit_type;
            p_nhdb->cvlan_edit_type = dsnh_param.p_vlan_info->cvlan_edit_type;
            CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_ERSPAN_EN);
        }
        if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));
        }
    }
    else if (p_over_l2_edit && edit_dsnh)
    {
        CTC_ERROR_RETURN(_sys_usw_nh_misc_build_l2_edit(lchip, p_nh_misc, p_nhdb));

        dsnh_param.over_l2_edit = 1;
        dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_IPTUNNEL;
        dsnh_param.dest_vlan_ptr = dest_vlan_ptr;

        if (p_nhdb->dsl3edit_offset)
        {
            dsnh_param.inner_l2edit_ptr  = p_nhdb->dsl2edit_offset;
            dsnh_param.l3edit_ptr  = p_nhdb->dsl3edit_offset;
            if (0 == dsnh_param.inner_l2edit_ptr)
            {
                dsnh_param.only_l3edit = 1;
            }
        }
        else
        {
            dsnh_param.l2edit_ptr  = p_nhdb->dsl2edit_offset;
        }
        dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
        dsnh_param.span_id     = p_over_l2_edit->flow_id;
        if (p_over_l2_edit->flag & CTC_MISC_NH_OVER_L2_EDIT_VLAN_EDIT)
        {
            dsnh_param.p_vlan_info = &p_over_l2_edit->vlan_info;
            p_nhdb->svlan_edit_type = dsnh_param.p_vlan_info->svlan_edit_type;
            p_nhdb->cvlan_edit_type = dsnh_param.p_vlan_info->cvlan_edit_type;
        }

        if (p_over_l2_edit->ether_type == 0x894F &&  g_usw_nh_master[lchip]->nsh != NULL)
        {
            dsnh_param.strip_l2_hdr = 1;
        }
        else
        {
            CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_ERSPAN_EN);
        }

        CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param));
    }


    if (p_fp_edit && edit_dsnh)
    {
        sys_nh_info_dsnh_t fp_info;
        sal_memset(&fp_info, 0, sizeof(fp_info));
        CTC_ERROR_RETURN(MCHIP_NH(lchip)->get_fp_info(lchip, p_fp_edit->fp_id, (void*)&fp_info));

        if (0 == fp_info.fp2)
        {
            dsnh_param.l3edit_ptr = fp_info.l3_edit_ptr;
            dsnh_param.lspedit_ptr = fp_info.pair_edit_ptr;
        }
        else
        {
            p_nh_misc->xeditptr = fp_info.l3_edit_ptr;
            CTC_ERROR_RETURN(_sys_usw_nh_misc_build_l2_edit(lchip, p_nh_misc, p_nhdb));
            dsnh_param.l2edit_ptr = p_nhdb->dsl2edit_offset;
        }
        dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_OF;
        dsnh_param.dest_vlan_ptr = dest_vlan_ptr;
        dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
        dsnh_param.span_id = p_fp_edit->span_id;
        if(CTC_FLAG_ISSET(p_fp_edit->flag, CTC_MISC_NH_FP_FLAG_OP_BRIDGE))
        {
            CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_MISC_FLEX_PLD_BRIDGE);
        }
        if(CTC_FLAG_ISSET(p_fp_edit->flag, CTC_MISC_NH_FP_FLAG_MTU_NO_CHK))
        {
            dsnh_param.mtu_no_chk = 1;
        }
        if(CTC_FLAG_ISSET(p_fp_edit->flag, CTC_MISC_NH_FP_FLAG_REBACK))
        {
            uint16 lport = 0;
            uint8 lb_with_ldp = CTC_FLAG_ISSET(p_nh_misc->p_misc_param->flag, CTC_MISC_NH_FLAG_LB_WITH_LOGIC_DST_PORT);
            if (dsnh_param.lspedit_ptr)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "if lspedit_ptr exist, donot support config l2loopback edit!\n");
                return CTC_E_INVALID_CONFIG;
            }
            CTC_ERROR_RETURN(sys_usw_nh_add_loopback_l2edit(lchip, 0, lb_with_ldp, TRUE, &offset));
            p_nhdb->dsl2edit_offset = offset;
            sys_usw_get_gchip_id(lchip, &gchip);
            sys_usw_internal_port_get_rsv_port(lchip, SYS_INTERNAL_PORT_TYPE_ELOOP, p_nh_misc->p_misc_param->gport, &lport);
            p_nhdb->gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);
            dsnh_param.l2edit_ptr = p_nhdb->dsl2edit_offset;
            if (lb_with_ldp)
            {
                CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LB_WITH_LOGIC_DST);
                dsnh_param.dvp_tbl_valid =1;
            }
        }
        if (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_MISC_NH_FP_FLAG_REPLACE_L2HDR))
        {
            if (dsnh_param.lspedit_ptr)
            {
                SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "if lspedit_ptr exist, donot support config replace l2hdr edit!\n");
                return CTC_E_INVALID_CONFIG;
            }
            dsnh_param.l2edit_ptr = g_usw_nh_master[lchip]->ecmp_if_resolved_l2edit;
            dsnh_param.outer_edit_location = 1;
        }
        if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));

        }
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_misc_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1)
{
    sys_nh_param_dsfwd_t dsfwd_param;
    sys_nh_info_misc_t* p_nhdb = (sys_nh_info_misc_t*)(p_com_db);
    uint8 truncate_proflile = 0;
    int32 ret = CTC_E_NONE;

    sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
    dsfwd_param.dest_chipid = SYS_MAP_CTC_GPORT_TO_GCHIP(p_nhdb->gport);
    dsfwd_param.dest_id = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_nhdb->gport);
    dsfwd_param.is_cpu  = CTC_IS_CPU_PORT(p_nhdb->gport);
    dsfwd_param.is_mcast = FALSE;
    dsfwd_param.is_reflective = p_nhdb->is_reflective;
    dsfwd_param.is_egress_edit =  CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);


    if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        dsfwd_param.nexthop_ext = 1;
    }

    if (p_nhdb->truncated_len)
    {
        ret = sys_usw_register_get_truncation_profile_id(lchip, p_nhdb->truncated_len, CTC_UINT16_BITS, &truncate_proflile);
        dsfwd_param.truncate_profile_id = truncate_proflile;
    }

    dsfwd_param.is_6w = dsfwd_param.truncate_profile_id || dsfwd_param.stats_ptr || dsfwd_param.is_reflective;
    dsfwd_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;
    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, is_dsfwd1));

    return ret;
}
int32
_sys_usw_nh_free_misc_nh_resource(uint8 lchip, sys_nh_info_misc_t* p_nhinfo)
{
    uint32 offset = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_PTR_VALID_CHECK(p_nhinfo);

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW))
    {
        return CTC_E_NONE;
    }

    if (p_nhinfo->vlan_profile_id)
    {
        sys_dsl2edit_vlan_edit_t vlan_edit;
        sal_memset(&vlan_edit, 0, sizeof(sys_dsl2edit_vlan_edit_t));

        CTC_ERROR_RETURN(sys_usw_nh_get_asic_table(lchip,  SYS_NH_ENTRY_TYPE_L2EDIT_VLAN_PROFILE,
                    p_nhinfo->vlan_profile_id, &(vlan_edit.data)));
        _sys_usw_nh_misc_l2edit_remove_vlan_edit_spool(lchip, &vlan_edit);
        p_nhinfo->vlan_profile_id = 0;
    }
    if (p_nhinfo->is_loop_nh
        ||((p_nhinfo->misc_nh_type == CTC_MISC_NH_TYPE_FP_EDIT) && CTC_FLAG_ISSET(p_nhinfo->flag, CTC_MISC_NH_FP_FLAG_REBACK)))
    {
        sys_usw_nh_remove_loopback_l2edit(lchip, p_nhinfo->dsl2edit_offset, TRUE);
        p_nhinfo->is_loop_nh = 0;
    }
    else if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
    {
        sys_usw_nh_remove_l2edit(lchip, p_nhinfo->l2edit_entry_type, p_nhinfo->dsl2edit_offset);
    }
    else if(DRV_FROM_TMM(lchip))
    {
        offset = p_nhinfo->dsl2edit_offset;
        _sys_usw_nh_misc_build_outer_l2_for_mpls(lchip, &offset, 0);

        if (p_nhinfo->l3edit_entry_type == SYS_NH_ENTRY_TYPE_L3EDIT_FP)
        {
            CTC_ERROR_RETURN(MCHIP_NH(lchip)->remove_fp(lchip, p_nhinfo->dsl3edit_offset));
        }
    }

    /*TODO>>>*/
    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT))
    {
        sys_usw_nh_remove_l3edit_tunnel(lchip, p_nhinfo->l3edit_entry_type, p_nhinfo->dsl3edit_offset);
        if (p_nhinfo->next_l3edit_offset)
        {
            sys_usw_nh_remove_l3edit_tunnel(lchip, p_nhinfo->next_l3edit_entry_type, p_nhinfo->next_l3edit_offset);
        }
    }

    if (p_nhinfo->truncated_len && p_nhinfo->misc_nh_type != CTC_MISC_NH_TYPE_TO_CPU)
    {
        p_nhinfo->truncated_len = 0;/*?*/
    }

    p_nhinfo->dsl3edit_offset = 0;
    p_nhinfo->dsl2edit_offset = 0;
    CTC_UNSET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT);
    CTC_UNSET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);

    return CTC_E_NONE;
}

int32
sys_usw_nh_add_erspan_edit(uint8 lchip, ctc_misc_nh_erspan_t* erspan_param, uint32 *p_fp_id)
{
    int32 ret = CTC_E_NONE;
    uint8 index = 0;
    uint8 update_truncate = 0;
    uint8 insert_len = 0;
    uint8 oper_valid = 0;
    uint8 raw_data[20] = {0x00};
    ctc_nh_fp_edit_t fp_edit;
    ctc_nh_fp_field_t* p_field;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    update_truncate = CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_TRUNCATED);

    /* check param */
    if(!update_truncate)
    {
        CTC_VALUE_RANGE_CHECK(erspan_param->version, 1, 2);
        CTC_MAX_VALUE_CHECK(erspan_param->session_id, 0x3FF);
        CTC_MAX_VALUE_CHECK(erspan_param->hw_id, 0x3F);
        CTC_MAX_VALUE_CHECK(erspan_param->switch_id, 0x3FF);
        CTC_MAX_VALUE_CHECK(erspan_param->direction, CTC_EGRESS);
    }

    p_field = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(ctc_nh_fp_field_t) * CTC_NH_FP_FIELD_MAX);
    if(p_field == NULL)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_field, 0, sizeof(ctc_nh_fp_field_t) * CTC_NH_FP_FIELD_MAX);
    sal_memset(&fp_edit, 0, sizeof(fp_edit));

    if(update_truncate)
    {
        /* update packet len in ip header */
        p_field[index].offset = erspan_param->ip_ver ? 32 : 16;
        p_field[index].len = 16;
        p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
        p_field[index].data.type = CTC_NH_FP_DATA_RAW;
        p_field[index].data.len = 16;
        p_field[index].data.value = erspan_param->ip_len;
        index++;

        /* update truncation flag in erspan type3 header */
        p_field[index].offset = erspan_param->ip_ver ? 373 /* 44*8 + 16+5 */: 213/* 24*8 + 16 + 5*/;
        p_field[index].len = 1;
        p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
        p_field[index].data.type = CTC_NH_FP_DATA_RAW;
        p_field[index].data.len = 1;
        p_field[index].data.value = 1;
        index++;

        fp_edit.p_field_list = p_field;
        fp_edit.field_cnt = index;
        fp_edit.edit_type = CTC_NH_FP_EDIT_REP;
        fp_edit.offset_type = CTC_PKT_OFFSET_L3;
        fp_edit.offset = 0;

        /* update packet checksun in ip header, only for ipv4 */
        if(erspan_param->ip_ver == 0)
        {
            fp_edit.l3chksum.enable = 1;
            fp_edit.l3chksum.offset = 10;
            fp_edit.l3chksum.mask = 0xffff;
        }
    }
    else
    {
        /* fix fp edit param */
        /* version(4bit) + vlan(12bit) */
        p_field[index].offset = 0;
        p_field[index].len = 4;
        p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
        p_field[index].data.type = CTC_NH_FP_DATA_RAW;
        p_field[index].data.len = 4;
        p_field[index].data.value = erspan_param->version;
        index++;

        /* cos(3b) + bso(2b) + T(1b) + session_id(10b) */
        p_field[index].offset = 16;
        p_field[index].len = 16;
        p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
        p_field[index].data.type = CTC_NH_FP_DATA_SPAN_ID;
        p_field[index].data.len = 16;
        index++;

        /*                        ERSPAN Type II header
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |  Ver  |       VLAN            | COS | En|T|     Session ID    |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |       Reserved        |                Index                  |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
        if(erspan_param->version == 1)
        {
            /* reserve(12bit) + D(1bit) */
            p_field[index].offset = 32+12;
            p_field[index].len = 1;
            p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
            p_field[index].data.type = CTC_NH_FP_DATA_RAW;
            p_field[index].data.len = 1;
            p_field[index].data.value = erspan_param->direction;
            index++;

            /* Index(19bit) */
            if(CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_SRC_PORT_EN))
            {
                p_field[index].offset = 48;
                p_field[index].len = 16;
                p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
                p_field[index].data.type = CTC_NH_FP_DATA_SRC_PORT;
                p_field[index].data.len = 16;
                index++;
            }

            insert_len = 8;
        }
        else if(erspan_param->version == 2)
        {
         /*                   ERSPAN Type III header (12 octets)
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |  Ver  |       VLAN            | COS | En|T|     Session ID    |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                          Timestamp                            |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |              SGT              |P|    FT   |   Hw ID   |D|Gra|O|
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
            uint8 ts_gra = 0x03;
            if(CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_TS_EN))
            {
                 /* ts (32b) */
                p_field[index].offset = 32;
                p_field[index].len = 32;
                p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
                p_field[index].data.type = (erspan_param->direction == CTC_INGRESS) ? CTC_NH_FP_DATA_IGS_TS_LOW : CTC_NH_FP_DATA_TS_LOW;
                p_field[index].data.len = 32;
                index++;
                ts_gra = 0x02;
            }

            oper_valid = erspan_param->switch_id || CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_SRC_PORT_EN) || CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_TS_EN);
            /* SGT(16b) + P(1b) + FT(5b) + Hw_id(6b) + D(1b) + Gra(2b) + O(1b)*/
            p_field[index].offset = 64;
            p_field[index].len = 16;
            p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
            p_field[index].data.type = CTC_NH_FP_DATA_RAW;
            p_field[index].data.len = 16;
            p_field[index].data.value = erspan_param->sgt_id;
            index++;

            /* SGT(16b) + P(1b) + FT(5b) + Hw_id(6b) + D(1b) + Gra(2b) + O(1b)*/
            p_field[index].offset = 80;
            p_field[index].len = 8;
            p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
            p_field[index].data.type = CTC_NH_FP_DATA_RAW;
            p_field[index].data.len = 8;
            p_field[index].data.value = erspan_param->hw_id >> 4;
            index++;

            /* SGT(16b) + P(1b) + FT(5b) + Hw_id(6b) + D(1b) + Gra(2b) + O(1b)*/
            p_field[index].offset = 88;
            p_field[index].len = 8;
            p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
            p_field[index].data.type = CTC_NH_FP_DATA_RAW;
            p_field[index].data.len = 8;
            p_field[index].data.value = (erspan_param->hw_id << 4) | (erspan_param->direction << 3) | (ts_gra << 1) | oper_valid;
            index++;

            insert_len = 12;
            if(oper_valid)
            {
              /*        Platform Specific SubHeader (8 octets, optional)
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                | Platf ID |                Platform Specific Info              |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                       Platform Specific Info                  |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
                /* platform id 0x05-0x06 format: */
                /* platform_id(6b) + switch_id(10b)*/
                p_field[index].offset = 96;
                p_field[index].len = 16;
                p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
                p_field[index].data.type = CTC_NH_FP_DATA_RAW;
                p_field[index].data.len = 16;
                p_field[index].data.value = (0x05 << 10) | erspan_param->switch_id;
                index++;

                /* port_id(16b) */
                if(CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_SRC_PORT_EN))
                {
                    p_field[index].offset = 112;
                    p_field[index].len = 16;
                    p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
                    p_field[index].data.type = CTC_NH_FP_DATA_SRC_PORT;
                    p_field[index].data.len = 16;
                    index++;
                }

                /* ts_high(32b) */
                if(CTC_FLAG_ISSET(erspan_param->flag, CTC_MISC_NH_ERSPAN_TS_EN))
                {
                    p_field[index].data.type = (erspan_param->direction == CTC_INGRESS) ? CTC_NH_FP_DATA_IGS_TS_HIGH : CTC_NH_FP_DATA_TS_HIGH;
                    p_field[index].offset = 128;
                    p_field[index].len = 32;
                    p_field[index].zone = CTC_NH_FP_ZONE_PACKET;
                    p_field[index].data.len = 32;
                    index++;
                }

                insert_len = 20;
            }
        }

        fp_edit.p_field_list = p_field;
        fp_edit.field_cnt = index;
        fp_edit.edit_type = CTC_NH_FP_EDIT_INS;
        fp_edit.data = raw_data;
        fp_edit.offset_type = CTC_PKT_OFFSET_L2;
        fp_edit.offset = 0;
        fp_edit.len = insert_len;

        /*usw zone CTC_NH_FP_ZONE_PACKET*/
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_REP_SEL_VALID);
        fp_edit.replace_sel = 1;
    }

    if (MCHIP_NH(lchip)->add_fp)
    {
        ret = MCHIP_NH(lchip)->add_fp(lchip, &fp_edit, 0);
        *p_fp_id = fp_edit.fp_id;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%% The allocate fp_id is %d.\n", fp_edit.fp_id);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
    }

    mem_free(p_field);
    return ret;
}

int32
_sys_usw_nh_get_reason_nhinfo(uint8 lchip, sys_cpu_reason_dest_info_t* p_dest_info, uint16 reason_id,
                                           uint32* nexthop_ptr,uint8* dsnh_8w)
{
    uint8 dest_type = 0;
    uint32 nhid = 0;
    sys_nh_info_dsnh_t nh_info;
    uint8 cpu_mac_id = 0;

    sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));
    dest_type = p_dest_info->dest_type;
    if(dest_type == CTC_PKT_CPU_REASON_TO_LOCAL_PORT)
    {
        CTC_ERROR_RETURN(sys_usw_l2_get_ucast_nh(lchip, p_dest_info->dest_port, CTC_NH_PARAM_BRGUC_SUB_TYPE_BYPASS, &nhid));
        /*get nexthop info from nexthop id */
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, nhid, &nh_info, 1));
    }
    else if(dest_type == CTC_PKT_CPU_REASON_TO_NHID)
    {
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, p_dest_info->dest_port, &nh_info, 1));
    }
    else if(dest_type == CTC_PKT_CPU_REASON_TO_LOCAL_CPU_ETH)
    {
        if(DRV_FROM_TMM(lchip))
        {
            *nexthop_ptr = CTC_PKT_CPU_REASON_BUILD_NHPTR(reason_id,  p_dest_info->sub_idx);
        }
        else
        {
            cpu_mac_id = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_dest_info->dest_port);
            *nexthop_ptr = CTC_PKT_CPU_REASON_BUILD_NHPTR(reason_id, cpu_mac_id);
        }
    }
    else if(dest_type == CTC_PKT_CPU_REASON_TO_REMOTE_CPU)
    {
        if(DRV_FROM_TMM(lchip) &&(((p_dest_info->dest_port >> CTC_TYPE_PORT_OFFSET) & CTC_TYPE_PORT_MASK) == CTC_GPORT_TYPE_CPU_MAC))
        {
            cpu_mac_id = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_dest_info->dest_port)&0x3;
        }
        *nexthop_ptr = CTC_PKT_CPU_REASON_BUILD_NHPTR(reason_id, cpu_mac_id);
    }
    else
    {
        *nexthop_ptr = CTC_PKT_CPU_REASON_BUILD_NHPTR(reason_id, 0);
    }
    if(dest_type == CTC_PKT_CPU_REASON_TO_LOCAL_PORT || dest_type == CTC_PKT_CPU_REASON_TO_NHID)
    {
        *nexthop_ptr = nh_info.dsnh_offset;
        CTC_BIT_UNSET(*nexthop_ptr, 17); /* bit 17 used for bypass ingress edit */
        *dsnh_8w = nh_info.nexthop_ext;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_nh_alloc_reason_dsfwd_offset(uint8 lchip, uint16 reason_id, uint32 nh_id,
                                           uint32 *dsfwd_offset,
                                           uint32 *dsnh_offset,
                                           uint32 *dest_port)
{
    sys_cpu_reason_dest_info_t dest_info;
    uint8 critical_packet = 0;
    uint32 nexthop_ptr = 0;
    uint8 dsnh_8w = 0;
    uint8 del = (dsnh_offset == NULL)?1:0;
    sys_nh_update_dsfwd_t update_dsfwd_param;
    sys_nh_info_dsnh_t  nh_info;
    int32 ret = CTC_E_NONE;

    CTC_MIN_VALUE_CHECK(reason_id, CTC_PKT_CPU_REASON_CUSTOM_BASE);
    CTC_MAX_VALUE_CHECK(reason_id, CTC_PKT_CPU_REASON_MAX_COUNT - 1);

    sal_memset(&dest_info, 0, sizeof(dest_info));
    CTC_ERROR_RETURN(sys_usw_cpu_reason_get_info(lchip, reason_id, &dest_info));
    if (dest_info.user_define_mode == 2)
    {
        return CTC_E_IN_USE;
    }
    if (NULL != dsnh_offset && 0 != dest_info.nexthop_id && nh_id != dest_info.nexthop_id)
    {
        /*not support misc nh:cpu reason is N : 1*/
        return CTC_E_NOT_SUPPORT;
    }
    if ((CTC_PKT_CPU_REASON_TO_LOCAL_CPU == dest_info.dest_type)|| (CTC_PKT_CPU_REASON_TO_REMOTE_CPU == dest_info.dest_type)
         || (CTC_PKT_CPU_REASON_TO_LOCAL_CPU_ETH == dest_info.dest_type))
    {
        critical_packet = 1;
    }

    CTC_ERROR_RETURN(_sys_usw_nh_get_reason_nhinfo(lchip, &dest_info, reason_id, &nexthop_ptr, &dsnh_8w));
    sal_memset(&update_dsfwd_param, 0, sizeof(update_dsfwd_param));
    update_dsfwd_param.dest_map = dest_info.dest_map;
    update_dsfwd_param.dsnh_offset = nexthop_ptr;
    update_dsfwd_param.dsnh_8w = dsnh_8w;
    update_dsfwd_param.del = del;
    update_dsfwd_param.critical_packet = critical_packet;
    update_dsfwd_param.dsfwd_offset = (!dest_info.nexthop_id && dest_info.dest_type == CTC_PKT_CPU_REASON_TO_DROP) ? 0 : dsfwd_offset[0];
    update_dsfwd_param.dsfwd1_offset = (!dest_info.nexthop_id && dest_info.dest_type == CTC_PKT_CPU_REASON_TO_DROP) ? 0 : dsfwd_offset[1];
    if(dest_info.nexthop_id && !del)
    {
        sal_memset(&nh_info, 0, sizeof(nh_info));
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, dest_info.nexthop_id, &nh_info, 1));
        update_dsfwd_param.dsfwd_offset = nh_info.dsfwd_offset;
        update_dsfwd_param.dsfwd1_offset = nh_info.dsfwd1_offset;
    }
    CTC_ERROR_RETURN(sys_usw_nh_update_entry_dsfwd(lchip, &update_dsfwd_param));
    if (DRV_FROM_AT(lchip))
    {
        update_dsfwd_param.is_dsfwd1 = 1;
        ret = (sys_usw_nh_update_entry_dsfwd(lchip, &update_dsfwd_param));
        if (ret && (0 == del))
        {
            update_dsfwd_param.del = 1;
            update_dsfwd_param.is_dsfwd1 = 0;
            sys_usw_nh_update_entry_dsfwd(lchip, &update_dsfwd_param);
            return ret;
        }
    }
    if(del)
    {
        dest_info.nexthop_id = 0;
        dest_info.user_define_mode = 0;
    }
    else
    {
        dest_info.nexthop_id = nh_id;
        dsfwd_offset[0] = update_dsfwd_param.dsfwd_offset;
        dsfwd_offset[1] = update_dsfwd_param.dsfwd1_offset;
        *dsnh_offset = CTC_PKT_CPU_REASON_BUILD_NHPTR(reason_id, 0);
        if (dest_port)
        {
            *dest_port = dest_info.dest_port;
        }
        dest_info.user_define_mode = 1;
    }

    CTC_ERROR_RETURN(sys_usw_cpu_reason_set_info(lchip, reason_id, &dest_info));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "reason id:%u, user defined mode:%u\n", reason_id, dest_info.user_define_mode);

    return CTC_E_NONE;
}

int32
sys_usw_nh_create_misc_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_misc_t* p_nh_misc;
    int32 ret = 0;
    uint8 service_queue_egress_en = 0;

    sys_nh_info_misc_t* p_nhdb = NULL;
    ctc_misc_nh_param_t* p_tmp_misc_param = NULL;
    ctc_misc_nh_type_t misc_nh_type;
    uint32 dest_port = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    /* 1. sanity check & init */
    p_nh_misc = (sys_nh_param_misc_t*)p_com_nh_para;
    p_nhdb    = (sys_nh_info_misc_t*)p_com_db;
    p_tmp_misc_param = p_nh_misc->p_misc_param;
    misc_nh_type = p_tmp_misc_param->type;

    if (p_tmp_misc_param->logic_port && (p_tmp_misc_param->logic_port > MCHIP_CAP(SYS_CAP_MAX_LOGIC_PORT)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Invalid logic port\n");
        return CTC_E_INVALID_PORT;
    }

    if(CTC_MISC_NH_TYPE_REPLACE_L2HDR == misc_nh_type
		|| CTC_MISC_NH_TYPE_REPLACE_L2_L3HDR == misc_nh_type)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    if ((CTC_MISC_NH_TYPE_TO_CPU == misc_nh_type || CTC_MISC_NH_TYPE_LEAF_SPINE == misc_nh_type)
        && (p_tmp_misc_param->stats_id || p_tmp_misc_param->cid))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    if ((CTC_MISC_NH_TYPE_TO_CPU == misc_nh_type || CTC_IS_CPU_PORT(p_tmp_misc_param->gport))
        && p_tmp_misc_param->truncated_len)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    CTC_ERROR_RETURN(sys_usw_global_get_logic_destport_en(lchip,&service_queue_egress_en));
    if (service_queue_egress_en && p_tmp_misc_param->truncated_len)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    if (p_tmp_misc_param->stats_id && p_tmp_misc_param->cid && !CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Cnnot support stats and cid in 4w mode \n");
        return CTC_E_INVALID_CONFIG;
    }

    if (p_tmp_misc_param->stats_id)
    {
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip,
                                                           p_tmp_misc_param->stats_id,
                                                           &p_nh_misc->hdr.stats_ptr));
    }

    if(CTC_MISC_NH_TYPE_FLEX_EDIT_HDR == misc_nh_type)
    {
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.ecn, 3);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.dscp_or_tos, 63);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.new_stpid_idx, 3);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.packet_type, CTC_MISC_NH_PACKET_TYPE_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.stag_op, CTC_VLAN_TAG_OP_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.svid_sl, CTC_VLAN_TAG_SL_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.scos_sl, CTC_VLAN_TAG_SL_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.ctag_op, CTC_VLAN_TAG_OP_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.cvid_sl, CTC_VLAN_TAG_SL_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.ccos_sl, CTC_VLAN_TAG_SL_MAX - 1);
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.ecn_select, (MAX_CTC_NH_ECN_SELECT_MODE-1));
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.user_vlanptr, MCHIP_CAP(SYS_CAP_MAX_VLAN_PTR));
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.flex_edit.dscp_select, (MAX_CTC_NH_DSCP_SELECT_MODE-1));

        if (CTC_VLAN_TAG_SL_NEW == p_tmp_misc_param->misc_param.flex_edit.svid_sl)
        {
            CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.flex_edit.new_svid);
        }

        if (CTC_VLAN_TAG_SL_NEW == p_tmp_misc_param->misc_param.flex_edit.cvid_sl)
        {
            CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.flex_edit.new_cvid);
        }

        if (CTC_VLAN_TAG_SL_NEW == p_tmp_misc_param->misc_param.flex_edit.scos_sl)
        {
            CTC_COS_RANGE_CHECK(p_tmp_misc_param->misc_param.flex_edit.new_scos);
        }

        if (CTC_VLAN_TAG_SL_NEW == p_tmp_misc_param->misc_param.flex_edit.ccos_sl)
        {
            CTC_COS_RANGE_CHECK(p_tmp_misc_param->misc_param.flex_edit.new_ccos);
        }
        if ((!DRV_IS_DUET2(lchip)) && (!DRV_IS_TSINGMA(lchip))
            && (CTC_MISC_NH_PACKET_TYPE_ARP == p_tmp_misc_param->misc_param.flex_edit.packet_type)
            && CTC_FLAG_ISSET(p_tmp_misc_param->misc_param.flex_edit.flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_ARP_HDR))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Can not support replace arp header \n");
            return CTC_E_NOT_SUPPORT;
        }
    }
    else if((CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == misc_nh_type) || (CTC_MISC_NH_TYPE_OVER_L2 == misc_nh_type))
    {
        if (p_tmp_misc_param->misc_param.over_l2edit.vlan_id)
        {
            CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.vlan_id);
        }
        if (p_tmp_misc_param->misc_param.over_l2edit.cvlan_id)
        {
            CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.cvlan_id);
        }

        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.flow_id, 0x3FF);

        if (p_tmp_misc_param->misc_param.over_l2edit.flag & CTC_MISC_NH_OVER_L2_EDIT_VLAN_EDIT)
        {
            if (CTC_FLAG_ISSET(p_tmp_misc_param->misc_param.over_l2edit.vlan_info.edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_CVID_VALID))
            {
                CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.vlan_info.output_cvid);
            }

            if (CTC_FLAG_ISSET(p_tmp_misc_param->misc_param.over_l2edit.vlan_info.edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID))
            {
                CTC_VLAN_RANGE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.vlan_info.output_svid);
            }

            CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.vlan_info.user_vlanptr, MCHIP_CAP(SYS_CAP_MAX_VLAN_PTR));
        }
        CTC_MAX_VALUE_CHECK(p_tmp_misc_param->misc_param.over_l2edit.raw_data_len, SYS_L3EDIT_RAW_LEN_MAX*4);
        if (p_tmp_misc_param->misc_param.over_l2edit.raw_data_len % 2)
        {
            return CTC_E_INVALID_PARAM;
        }
    }
    else if(CTC_MISC_NH_TYPE_FP_EDIT == misc_nh_type)
    {
        ctc_misc_nh_fp_edit_param_t* p_fp_edit = NULL;
        p_fp_edit = (ctc_misc_nh_fp_edit_param_t *)&p_tmp_misc_param->misc_param.fp_edit;
        CTC_MAX_VALUE_CHECK(p_fp_edit->span_id, 0x3FF);
        if (CTC_FLAG_ISSET(p_fp_edit->flag, CTC_MISC_NH_FP_FLAG_REBACK | CTC_MISC_NH_FP_FLAG_REPLACE_L2HDR))
        {
            return CTC_E_INVALID_CONFIG;
        }
    }
    else if(CTC_MISC_NH_TYPE_ERSPAN == misc_nh_type)
    {
        uint32 fp_id = 0;
        ctc_misc_nh_erspan_t erspan_param;
        ctc_misc_nh_fp_edit_param_t* p_fp_edit = NULL;
        p_fp_edit = (ctc_misc_nh_fp_edit_param_t *)&p_tmp_misc_param->misc_param.fp_edit;

        sal_memcpy(&erspan_param, &p_tmp_misc_param->misc_param.erspan_edit, sizeof(erspan_param));
        CTC_ERROR_RETURN(sys_usw_nh_add_erspan_edit(lchip, &erspan_param, &fp_id));

        p_fp_edit->span_id = erspan_param.session_id;
        p_fp_edit->fp_id = fp_id;
        p_fp_edit->flag = 0;

        p_nhdb->dsl3edit_offset = fp_id;
        p_nhdb->l3edit_entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_FP;
    }

    p_nhdb->hdr.nh_entry_type   = SYS_NH_TYPE_MISC;
    p_nhdb->misc_nh_type        = misc_nh_type;


    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhType = %u, miscNhType = %u, NHID = %u, isInternaNH = %u, \n\
        gport = %d, dsnh_offset = %u\n",
                   p_nh_misc->hdr.nh_param_type,
                   misc_nh_type,
                   p_nh_misc->hdr.nhid,
                   p_nh_misc->hdr.is_internal_nh,
                   p_nh_misc->p_misc_param->gport,
                   p_nh_misc->p_misc_param->dsnh_offset);

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_COM, 1);
    if (CTC_MISC_NH_TYPE_TO_CPU == misc_nh_type)
    {
        uint32 dsfwd_offset[2] = {0};
        CTC_ERROR_RETURN(_sys_usw_nh_alloc_reason_dsfwd_offset(lchip, p_nh_misc->p_misc_param->misc_param.cpu_reason.cpu_reason_id, p_nh_misc->hdr.nhid,
                  dsfwd_offset,&p_nhdb->hdr.dsnh_offset, &dest_port));
        p_nhdb->hdr.dsfwd_offset = dsfwd_offset[0];
        p_nhdb->hdr.dsfwd1_offset = dsfwd_offset[1];
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_DSFWD_IS_6W);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_RSV_DSFWD);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
        p_nhdb->gport = dest_port;
        p_nhdb->truncated_len = p_nh_misc->p_misc_param->misc_param.cpu_reason.cpu_reason_id;
        p_nh_misc->hdr.have_dsfwd = 0;
        p_nh_misc->hdr.have_dsfwd1 = 0;
    }
    else if (CTC_MISC_NH_TYPE_LEAF_SPINE == misc_nh_type)
    {
        uint8 gchip = 0;

        p_nh_misc->hdr.have_dsfwd = 1;
        p_nh_misc->hdr.have_dsfwd1 = 1;
        gchip = CTC_MAP_GPORT_TO_GCHIP(p_nh_misc->p_misc_param->gport);
        SYS_GLOBAL_CHIPID_CHECK(gchip);

        p_nhdb->gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, SYS_RSV_PORT_SPINE_LEAF_PORT);
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
    }
    else
    {
        /*write l2edit and nexthop*/
        CTC_ERROR_GOTO(_sys_usw_nh_misc_write_dsnh(lchip,  p_nh_misc, p_nhdb),ret, error_proc);
    }

    if ((p_tmp_misc_param->truncated_len)&&(CTC_MISC_NH_TYPE_TO_CPU != misc_nh_type))
    {
        p_nhdb->truncated_len = p_tmp_misc_param->truncated_len;
        p_nh_misc->hdr.have_dsfwd = 1;
        p_nh_misc->hdr.have_dsfwd1 = 1;
    }

    /*3.Create Dwfwd*/
    if (p_nh_misc->hdr.have_dsfwd)
    {
        ret = _sys_usw_nh_misc_add_dsfwd(lchip, p_com_db, 0);
    }
    if (DRV_FROM_AT(lchip) && p_nh_misc->hdr.have_dsfwd1)
    {
        ret = ret? ret : _sys_usw_nh_misc_add_dsfwd(lchip, p_com_db, 1);
    }

error_proc:
	if(ret != CTC_E_NONE)
    {
        _sys_usw_nh_free_misc_nh_resource(lchip, p_nhdb);
    }
    return ret;

}

int32
sys_usw_nh_delete_misc_cb(uint8 lchip, sys_nh_info_com_t* p_flex_info, sys_nh_param_com_t* p_para)
{

    sys_nh_info_misc_t* p_nh_info;
    sys_nh_ref_list_node_t* p_ref_node, * p_tmp_node;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    p_nh_info = (sys_nh_info_misc_t*)(p_flex_info);

    /*2. Free DsFwd/DsNexthop/DsL2Edit offset*/

    if (p_nh_info->misc_nh_type == CTC_MISC_NH_TYPE_TO_CPU)
    {
        uint32 dsfwd_offset[2] = {0};
        dsfwd_offset[0] = p_nh_info->hdr.dsfwd_offset;
        dsfwd_offset[1] = p_nh_info->hdr.dsfwd1_offset;
        _sys_usw_nh_alloc_reason_dsfwd_offset(lchip, p_nh_info->truncated_len, p_nh_info->hdr.nh_id, dsfwd_offset, NULL, NULL);
        /* dsFwd table is already freed */
        CTC_UNSET_FLAG(p_flex_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD);
        CTC_UNSET_FLAG(p_flex_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1);
    }

    _sys_usw_nh_remove_dsfwd(lchip, p_flex_info);


    if(p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
    {
        sys_usw_nh_update_ecmp_member(lchip, p_flex_info->hdr.nh_id, SYS_NH_CHANGE_TYPE_NH_DELETE, p_para->hdr.p_nh_info_ext->ecmp_list);
        /*1. delete all reference ecmp nh*/
        p_ref_node = p_para->hdr.p_nh_info_ext->ecmp_list;

        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }
        p_para->hdr.p_nh_info_ext->ecmp_list = NULL;
    }
    if(p_nh_info->bind_data)
    {
        mem_free(p_nh_info->bind_data);
    }
    _sys_usw_nh_free_misc_nh_resource(lchip, p_nh_info);
    return CTC_E_NONE;
}

int32
sys_usw_nh_get_misc_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db, void* p_para)
{
    sys_nh_info_misc_t* p_nh_info;
    ctc_misc_nh_param_t* p_misc_param = NULL;
    uint16 ifid = 0;
    ctc_l3if_t l3if_info;
    int32 ret = 0;
    uint32 cmd = 0;
    hw_mac_addr_t hw_mac;
    sys_nexthop_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_PTR_VALID_CHECK(p_para);
    p_nh_info = (sys_nh_info_misc_t*)(p_nh_db);
    p_misc_param = (ctc_misc_nh_param_t*)p_para;

    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE))
    {
        p_misc_param->dsnh_offset = p_nh_db->hdr.dsnh_offset;
    }
    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LB_WITH_LOGIC_DST))
    {
        CTC_SET_FLAG(p_misc_param->flag, CTC_MISC_NH_FLAG_LB_WITH_LOGIC_DST_PORT);
    }
    p_misc_param->type = p_nh_info->misc_nh_type;
    p_misc_param->gport = p_nh_info->gport;
    if (p_misc_param->type != CTC_MISC_NH_TYPE_TO_CPU)
    {
        p_misc_param->truncated_len = p_nh_info->truncated_len;
    }

    sal_memset(&dsnh, 0, sizeof(dsnh));
    CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?
    SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W, p_nh_info->hdr.dsnh_offset, &dsnh));
    if (dsnh.cid_valid)
    {
        p_misc_param->cid = dsnh.cid;
    }
    if (dsnh.stats_ptr)
    {
        sys_usw_flow_stats_lookup_statsid(lchip, CTC_STATS_STATSID_TYPE_NEXTHOP, dsnh.stats_ptr, &p_misc_param->stats_id, CTC_EGRESS);
    }
    p_misc_param->logic_port = dsnh.logic_dest_port;


    if(p_nh_info->is_loop_nh)
    {
         sys_usw_nh_get_loopback_l2edit(  lchip, p_nh_info->dsl2edit_offset,&p_misc_param->loop_nhid, TRUE);
    }


    ifid = p_nh_info->l3ifid;
    sal_memset(&l3if_info, 0, sizeof(l3if_info));
    l3if_info.l3if_type = 0xff;
    if (!CTC_IS_CPU_PORT(p_misc_param->gport))
    {
        p_misc_param->oif.gport = p_nh_info->gport;
        ret = (sys_usw_l3if_get_l3if_id(lchip, &l3if_info, &ifid));
        if (ret != CTC_E_NOT_EXIST)
        {
            p_misc_param->oif.vid = l3if_info.vlan_id;
            p_misc_param->oif.cvid = l3if_info.cvlan_id;
            p_misc_param->is_oif = 1;
        }
    }

    if (p_misc_param->type == CTC_MISC_NH_TYPE_TO_CPU)
    {
        p_misc_param->misc_param.cpu_reason.cpu_reason_id = p_nh_info->truncated_len;
    }
    else if (p_misc_param->type == CTC_MISC_NH_TYPE_FLEX_EDIT_HDR)
    {
        ctc_misc_nh_flex_edit_param_t* p_flex_param = NULL;
        p_flex_param = &p_misc_param->misc_param.flex_edit;
        p_flex_param->is_reflective = p_nh_info->is_reflective;
        p_flex_param->packet_type = p_nh_info->packet_type;
        p_flex_param->user_vlanptr = dsnh.dest_vlan_ptr;
        p_flex_param->flag = p_nh_info->flag;
        p_flex_param->ctag_op = p_nh_info->ctag_op;
        p_flex_param->cvid_sl = p_nh_info->cvid_sl;
        p_flex_param->ccos_sl = p_nh_info->ccos_sl;
        p_flex_param->stag_op = p_nh_info->stag_op;
        p_flex_param->svid_sl = p_nh_info->svid_sl;
        p_flex_param->scos_sl = p_nh_info->scos_sl;

        if (MCHIP_NH(lchip)->get_misc_edit_param)
        {
            MCHIP_NH(lchip)->get_misc_edit_param(lchip, p_nh_db, p_para);
        }
        else
        {
        if (p_nh_info->packet_type == CTC_MISC_NH_PACKET_TYPE_MPLS)
        {
            uint8 index = 0;
            ds0_t mpls_edit;
            p_flex_param->label_num = p_nh_info->label_num;
            for (index = 0; index < p_nh_info->label_num; index++)
            {
                cmd = DRV_IOR(DsL3EditMpls3W_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, index?p_nh_info->next_l3edit_offset:p_nh_info->dsl3edit_offset, cmd, &mpls_edit));
                _sys_usw_nh_decode_dsmpls(lchip, &mpls_edit, &p_flex_param->label[index]);
            }
        }
        else if (p_nh_info->l2edit_entry_type == SYS_NH_ENTRY_TYPE_L2EDIT_SWAP)
        {
            DsL2EditSwap_m l2_swap;
            cmd = DRV_IOR(DsL2EditSwap_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, p_nh_info->dsl2edit_offset, cmd, &l2_swap);
            GetDsL2EditSwap(A, macDa_f, &l2_swap, hw_mac);
            SYS_USW_SET_USER_MAC(p_flex_param->mac_da, hw_mac);
            GetDsL2EditSwap(A, macSa_f, &l2_swap, hw_mac);
            SYS_USW_SET_USER_MAC(p_flex_param->mac_sa, hw_mac);
        }
        else if (p_nh_info->l2edit_entry_type == SYS_NH_ENTRY_TYPE_L2EDIT_OF_6W)
        {
            DsL2EditOf_m l2_edit;
            DsOfEditVlanActionProfile_m vlan_action;
            cmd = DRV_IOR(DsL2EditOf_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, p_nh_info->dsl2edit_offset, cmd, &l2_edit);
            GetDsL2EditOf(A, macDa_f, &l2_edit, hw_mac);
            SYS_USW_SET_USER_MAC(p_flex_param->mac_da, hw_mac);
            GetDsL2EditOf(A, macSa_f, &l2_edit, hw_mac);
            SYS_USW_SET_USER_MAC(p_flex_param->mac_sa, hw_mac);
            p_flex_param->ether_type = GetDsL2EditOf(V, etherType_f, &l2_edit);
            p_flex_param->new_svid = GetDsL2EditOf(V, sVlanId_f, &l2_edit);
            p_flex_param->new_scos = GetDsL2EditOf(V, sCos_f, &l2_edit);
            p_flex_param->new_cvid = GetDsL2EditOf(V, cVlanId_f, &l2_edit);
            p_flex_param->new_ccos = GetDsL2EditOf(V, cCos_f, &l2_edit);

            cmd = DRV_IOR(DsOfEditVlanActionProfile_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, p_nh_info->vlan_profile_id, cmd, &vlan_action);
            if (GetDsOfEditVlanActionProfile(V, sVlanTpidIndexEn_f, &vlan_action))
            {
                p_flex_param->new_stpid_en = 1;
                p_flex_param->new_stpid_idx = GetDsOfEditVlanActionProfile(V, sVlanTpidIndex_f, &vlan_action);
            }
        }

        if (p_nh_info->l3edit_entry_type == SYS_NH_ENTRY_TYPE_L3EDIT_OF_6W)
        {
            uint8 dscp_mode = 0;
            DsL3EditOf6W_m  edit_profile;

            cmd =  DRV_IOR(DsL3EditOf6W_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, p_nh_info->dsl3edit_offset, cmd, &edit_profile);
            p_flex_param->ip_da.ipv4 = GetDsL3EditOf6W(V, ipDa_f, &edit_profile);
            p_flex_param->ip_sa.ipv4 = GetDsL3EditOf6W(V, ipSa_f, &edit_profile);
            p_flex_param->protocol = GetDsL3EditOf6W(V, protocol_f, &edit_profile);
            p_flex_param->ttl = GetDsL3EditOf6W(V, ttl_f, &edit_profile);

            if (GetDsL3EditOf6W(V, ecnRemarkMode_f, &edit_profile))
            {
                p_flex_param->ecn_select = (GetDsL3EditOf6W(V, ecnRemarkMode_f, &edit_profile)==1)?CTC_NH_ECN_SELECT_ASSIGN:CTC_NH_ECN_SELECT_MAP;
                p_flex_param->ecn = (GetDsL3EditOf6W(V, tos_f, &edit_profile)&0x3);
            }

            dscp_mode = GetDsL3EditOf6W(V, dscpRemarkMode_f, &edit_profile);
            p_flex_param->dscp_select = (dscp_mode==1)?CTC_NH_DSCP_SELECT_ASSIGN:
                ((dscp_mode==2)?CTC_NH_DSCP_SELECT_MAP:((dscp_mode==3)?CTC_NH_DSCP_SELECT_PACKET:CTC_NH_DSCP_SELECT_NONE));
            p_flex_param->dscp_or_tos = ((GetDsL3EditOf6W(V, tos_f, &edit_profile)>> 2) & 0x3f);
            if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_ICMP)
            {
                p_flex_param->icmp_code = GetDsL3EditOf6W(V, l4DestPort_f, &edit_profile);
                p_flex_param->icmp_type = GetDsL3EditOf6W(V, l4SourcePort_f, &edit_profile);
            }
            else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_GRE)
            {
                p_flex_param->gre_key = ((GetDsL3EditOf6W(V, l4SourcePort_f, &edit_profile)<<16) | GetDsL3EditOf6W(V, l4DestPort_f, &edit_profile));
            }
            else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_UDPORTCP)
            {
                p_flex_param->l4_dst_port = GetDsL3EditOf6W(V, l4DestPort_f, &edit_profile);
                p_flex_param->l4_src_port = GetDsL3EditOf6W(V, l4SourcePort_f, &edit_profile);
            }
        }
        else if (p_nh_info->l3edit_entry_type == SYS_NH_ENTRY_TYPE_L3EDIT_OF_12W)
        {
            uint8 dscp_mode = 0;
            uint8 l4_valid = 0;
            DsL3EditOf12W_m edit_profile;
            DsL3EditOf12WIpv6L4_m ipv6_l4;

            cmd = DRV_IOR(DsL3EditOf12W_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, p_nh_info->dsl3edit_offset, cmd, &edit_profile);
            GetDsL3EditOf12W(A, u1_gIpv6L4_data_f, &edit_profile,  &ipv6_l4);

            if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_ARP)
            {
                DsL3EditOf12WArpData_m arp_data;
                GetDsL3EditOf12W(A, data_f, &edit_profile,  &arp_data);
                p_flex_param->arp_ht = GetDsL3EditOf12WArpData(V, hardwareType_f, &arp_data);
                p_flex_param->arp_halen = GetDsL3EditOf12WArpData(V, hardwareAddLen_f, &arp_data);
                p_flex_param->arp_op = GetDsL3EditOf12WArpData(V, opCode_f, &arp_data);
                p_flex_param->arp_pt = GetDsL3EditOf12WArpData(V, protocolType_f, &arp_data);
                p_flex_param->arp_palen = GetDsL3EditOf12WArpData(V, protocolAddLen_f, &arp_data);
                GetDsL3EditOf12WArpData(A, senderHardwareAdd_f, &arp_data, hw_mac);
                SYS_USW_SET_USER_MAC(p_flex_param->arp_sha, hw_mac);
                GetDsL3EditOf12WArpData(A, targetHardwareAdd_f, &arp_data, hw_mac);
                SYS_USW_SET_USER_MAC(p_flex_param->arp_tha, hw_mac);
                p_flex_param->arp_tpa = GetDsL3EditOf12WArpData(V, targetProtocolAdd_f, &arp_data);
                p_flex_param->arp_spa = GetDsL3EditOf12WArpData(V, senderProtocolAdd_f, &arp_data);
            }
            else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_ICMP)
            {
                p_flex_param->icmp_code = GetDsL3EditOf12WIpv6L4(V, l4DestPort_f, &ipv6_l4);
                p_flex_param->icmp_type = GetDsL3EditOf12WIpv6L4(V, l4SourcePort_f, &ipv6_l4);
                l4_valid= 1;
            }
            else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_GRE)
            {
                p_flex_param->gre_key = (GetDsL3EditOf12WIpv6L4(V, l4SourcePort_f, &ipv6_l4)<<16) | GetDsL3EditOf12WIpv6L4(V, l4DestPort_f, &ipv6_l4);
                l4_valid= 1;
            }
            else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_UDPORTCP)
            {
                p_flex_param->l4_dst_port = GetDsL3EditOf12WIpv6L4(V, l4DestPort_f, &ipv6_l4);
                p_flex_param->l4_src_port = GetDsL3EditOf12WIpv6L4(V, l4SourcePort_f, &ipv6_l4);
                l4_valid= 1;
            }
            else if(CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_PROTOCOL))
            {
                l4_valid = 1;
            }

            if (l4_valid)
            {
                ipv6_addr_t hw_ipv6_address;
                p_flex_param->flow_label = GetDsL3EditOf12WIpv6L4(V, flowLabel_f, &ipv6_l4);
                p_flex_param->protocol = GetDsL3EditOf12WIpv6L4(V, protocol_f, &ipv6_l4);
                p_flex_param->ttl = GetDsL3EditOf12WIpv6L4(V, ttl_f, &ipv6_l4);
                if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IPDA))
                {
                    GetDsL3EditOf12WIpv6L4(A, ip_f,         &ipv6_l4,  hw_ipv6_address);
                    p_flex_param->ip_da.ipv6[0] = (hw_ipv6_address[3]);
                    p_flex_param->ip_da.ipv6[1] = (hw_ipv6_address[2]);
                    p_flex_param->ip_da.ipv6[2] = (hw_ipv6_address[1]);
                    p_flex_param->ip_da.ipv6[3] = (hw_ipv6_address[0]);
                }
                else
                {
                    GetDsL3EditOf12WIpv6L4(A, ip_f,         &ipv6_l4,  hw_ipv6_address);
                    p_flex_param->ip_sa.ipv6[0] = (hw_ipv6_address[3]);
                    p_flex_param->ip_sa.ipv6[1] = (hw_ipv6_address[2]);
                    p_flex_param->ip_sa.ipv6[2] = (hw_ipv6_address[1]);
                    p_flex_param->ip_sa.ipv6[3] = (hw_ipv6_address[0]);
                }
                dscp_mode = GetDsL3EditOf12WIpv6L4(V, dscpRemarkMode_f , &ipv6_l4);
                p_flex_param->ecn_select = (GetDsL3EditOf12WIpv6L4(V, ecnRemarkMode_f, &ipv6_l4) == 1)?CTC_NH_ECN_SELECT_ASSIGN:CTC_NH_ECN_SELECT_MAP;
                p_flex_param->dscp_select = (dscp_mode == 1)?CTC_NH_DSCP_SELECT_ASSIGN:
                    ((dscp_mode == 2)?CTC_NH_DSCP_SELECT_MAP:((dscp_mode == 3)?CTC_NH_DSCP_SELECT_PACKET:CTC_NH_DSCP_SELECT_NONE));
                p_flex_param->dscp_or_tos = (GetDsL3EditOf12WIpv6L4(V, tos_f , &ipv6_l4)>>2) & 0x3f;
             }
             else
             {
                 DsL3EditOf12WIpv6Only_m ipv6_only;
                 ipv6_addr_t hw_ipv6_address;
                 GetDsL3EditOf12W(A, u1_gIpv6Only_data_f, &edit_profile,  &ipv6_only);
                 p_flex_param->flow_label = GetDsL3EditOf12WIpv6Only(V, flowLabel_f, &ipv6_only);
                 p_flex_param->ttl = GetDsL3EditOf12WIpv6Only(V, ttl_f, &ipv6_only);
                if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IPSA))
                {
                    GetDsL3EditOf12WIpv6Only(A, ipSa_f,         &ipv6_only,  hw_ipv6_address);
                    p_flex_param->ip_sa.ipv6[0] = (hw_ipv6_address[3]);
                    p_flex_param->ip_sa.ipv6[1] = (hw_ipv6_address[2]);
                    p_flex_param->ip_sa.ipv6[2] = (hw_ipv6_address[1]);
                    p_flex_param->ip_sa.ipv6[3] = (hw_ipv6_address[0]);
                }

                if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IPDA))
                {
                    GetDsL3EditOf12WIpv6Only(A, ipDa_f,         &ipv6_only,  hw_ipv6_address);
                    p_flex_param->ip_da.ipv6[0] = (hw_ipv6_address[3]);
                    p_flex_param->ip_da.ipv6[1] = (hw_ipv6_address[2]);
                    p_flex_param->ip_da.ipv6[2] = (hw_ipv6_address[1]);
                    p_flex_param->ip_da.ipv6[3] = (hw_ipv6_address[0]);
                }
             }
        }
    }
    }
    else if ((p_misc_param->type == CTC_MISC_NH_TYPE_OVER_L2_WITH_TS) || (p_misc_param->type == CTC_MISC_NH_TYPE_OVER_L2))
    {
        uint32 cmd = 0;
        DsNextHop8W_m ds_nh;
        ctc_vlan_egress_edit_info_t* p_vlan_info;
        sys_dsl2edit_eth_t dsl2edit;
        cmd = DRV_IOR(DsNextHop8W_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nh_info->hdr.dsnh_offset, cmd, &ds_nh));
        p_misc_param->misc_param.over_l2edit.flag = p_nh_info->flag;
        p_misc_param->misc_param.over_l2edit.flow_id = GetDsNextHop8W(V, globalSpanId_f, &ds_nh);
        p_misc_param->misc_param.over_l2edit.vlan_info.user_vlanptr = dsnh.dest_vlan_ptr;

        if (p_nh_info->flag & CTC_MISC_NH_OVER_L2_EDIT_VLAN_EDIT)
        {
            p_vlan_info = &p_misc_param->misc_param.over_l2edit.vlan_info;
            p_vlan_info->svlan_edit_type = p_nh_info->svlan_edit_type;
            p_vlan_info->cvlan_edit_type = p_nh_info->cvlan_edit_type;
            _sys_usw_nh_decode_vlan_edit(lchip, p_vlan_info, &ds_nh);
        }

        if (p_nh_info->l3edit_entry_type == SYS_NH_ENTRY_TYPE_L3EDIT_FP)
        {
            sys_nh_fp_db_t *p_fp_db = NULL;
            uint8 data[40];
            uint8 *  drv_data = NULL;
            uint8 len = 40;
            uint8 i = 0;

            if (MCHIP_NH(lchip)->get_fp_db == NULL)
            {
                return CTC_E_NONE;
            }

            CTC_ERROR_RETURN(MCHIP_NH(lchip)->get_fp_db(lchip, p_nh_info->dsl3edit_offset, (void*)&p_fp_db));
            drv_data = (uint8*)p_fp_db->p_data_prof->data;


            do {
                data[i*4 + 3] = drv_data[i*4 + 0];
                data[i*4 + 2] = drv_data[i*4 + 1];
                data[i*4 + 1] = drv_data[i*4 + 2];
                data[i*4 + 0] = drv_data[i*4 + 3];
                len = len - 4;
                i++;
            }while (len > 0);

            sal_memcpy(&p_misc_param->misc_param.over_l2edit.mac_da, data, sizeof(mac_addr_t));
            sal_memcpy(&p_misc_param->misc_param.over_l2edit.mac_sa, data + 6, sizeof(mac_addr_t));
            p_misc_param->misc_param.over_l2edit.ether_type = ((data[12] << 8) | data[13]);

            if (p_misc_param->misc_param.over_l2edit.ether_type == 0x8100)
            {
                p_misc_param->misc_param.over_l2edit.vlan_id = ((data[14] << 8) | data[15]);
                p_misc_param->misc_param.over_l2edit.ether_type = ((data[16] << 8) | data[17]);
            }

            return CTC_E_NONE;
        }

        sal_memset(&dsl2edit, 0, sizeof(dsl2edit));
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_nh_info->l2edit_entry_type, p_nh_info->dsl2edit_offset, &dsl2edit));

        p_misc_param->misc_param.over_l2edit.ether_type = dsl2edit.ether_type;
        p_misc_param->misc_param.over_l2edit.vlan_id = dsl2edit.output_vid;
        sal_memcpy(&p_misc_param->misc_param.over_l2edit.mac_da, &dsl2edit.mac_da, sizeof(mac_addr_t));
        sal_memcpy(&p_misc_param->misc_param.over_l2edit.mac_sa, &dsl2edit.mac_sa, sizeof(mac_addr_t));

        if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT) && p_misc_param->misc_param.over_l2edit.raw_data)
        {
            sys_dsl3edit_raw_t l3edit_raw;
            uint32 data_tmp[SYS_L3EDIT_RAW_LEN_MAX] = {0};
            CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, p_nh_info->l3edit_entry_type, p_nh_info->dsl3edit_offset, &l3edit_raw));
            p_misc_param->misc_param.over_l2edit.raw_data_len = l3edit_raw.data_len;
            sys_usw_dword_reverse_copy(data_tmp, l3edit_raw.data, SYS_L3EDIT_RAW_LEN_MAX);
            sys_usw_swap32(data_tmp, SYS_L3EDIT_RAW_LEN_MAX, FALSE);
            sal_memcpy(p_misc_param->misc_param.over_l2edit.raw_data, (uint8*)data_tmp, l3edit_raw.data_len);
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_update_misc_fwd_attr(uint8 lchip, sys_nh_param_misc_t* p_nhpara,
                                            sys_nh_info_misc_t* p_nhinfo)
{
    sys_nh_param_misc_t* p_para = (sys_nh_param_misc_t*)p_nhpara;
    sys_nh_info_misc_t old_nh_info;
    int32 ret = 0;
    uint8 is_update = (p_nhpara->hdr.change_type != SYS_NH_CHANGE_TYPE_NULL);
    uint32 dsnh_offset = 0;
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    uint8 edit_dsnh = 1;
    DsNextHop8W_m data_w;
    uint16 span_id = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (CTC_MISC_NH_TYPE_FP_EDIT == p_para->p_misc_param->type)
    {
        span_id = p_para->p_misc_param->misc_param.fp_edit.span_id;
    }
    else if(CTC_MISC_NH_TYPE_ERSPAN == p_para->p_misc_param->type)
    {
        span_id = p_para->p_misc_param->misc_param.erspan_edit.session_id;
    }

    if (!CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)
    && ((CTC_MISC_NH_TYPE_OVER_L2_WITH_TS == p_para->p_misc_param->type) ||
         (CTC_MISC_NH_TYPE_OVER_L2 == p_para->p_misc_param->type) ||
        (p_para->p_misc_param->cid && !g_usw_nh_master[lchip]->cid_use_4w) ||
        (p_para->p_misc_param->stats_id && g_usw_nh_master[lchip]->cid_use_4w) ||
        span_id || p_para->p_misc_param->logic_port )
    && (!CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
    {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Should use DsNexthop8W table \n");
       return CTC_E_INVALID_CONFIG;
    }
    edit_dsnh = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW)? 0 : 1;
    if(is_update)
    {
        /*store nh old data, for recover*/
        sal_memcpy(&old_nh_info, p_nhinfo, sizeof(sys_nh_info_misc_t));
        sal_memset(p_nhinfo, 0, sizeof(sys_nh_info_misc_t));
        sys_usw_nh_copy_nh_entry_flags(lchip, &old_nh_info.hdr, &p_nhinfo->hdr);
        p_nhinfo->bind_data = old_nh_info.bind_data;

        tbl_id = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)? DsNextHop8W_t : DsNextHop4W_t;
        sal_memset(&data_w, 0, sizeof(DsNextHop8W_m));
        dsnh_offset = p_nhinfo->hdr.dsnh_offset;
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);
    }

    CTC_ERROR_GOTO(sys_usw_nh_create_misc_cb(lchip, (sys_nh_param_com_t*)p_nhpara,
        (sys_nh_info_com_t*)p_nhinfo), ret, error_proc);

    /*for update free resource here*/
   if(is_update)
   {
        if (old_nh_info.misc_nh_type == CTC_MISC_NH_TYPE_TO_CPU
            && old_nh_info.hdr.dsfwd_offset != p_nhinfo->hdr.dsfwd_offset)
        {
            uint32 dsfwd_offset[2] = {0};
            dsfwd_offset[0] = old_nh_info.hdr.dsfwd_offset;
            dsfwd_offset[1] = old_nh_info.hdr.dsfwd1_offset;
            _sys_usw_nh_alloc_reason_dsfwd_offset(lchip, old_nh_info.truncated_len, old_nh_info.hdr.nh_id, dsfwd_offset, NULL, NULL);
        }

        _sys_usw_nh_free_misc_nh_resource(lchip, &old_nh_info);
   }
   return CTC_E_NONE;
error_proc:
   if(is_update && edit_dsnh)
   {
       sal_memcpy( p_nhinfo, &old_nh_info,sizeof(sys_nh_info_misc_t));
        tbl_id = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?DsNextHop8W_t:DsNextHop4W_t;
        dsnh_offset = p_nhinfo->hdr.dsnh_offset;
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);
   }
   return ret;

}

int32
sys_usw_nh_update_misc_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db,
                                sys_nh_param_com_t* p_para)
{
    sys_nh_info_misc_t* p_nh_info;
    sys_nh_param_misc_t* p_nh_para;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_EQUAL_CHECK(SYS_NH_TYPE_MISC, p_nh_db->hdr.nh_entry_type);
    p_nh_info = (sys_nh_info_misc_t*)(p_nh_db);
    p_nh_para = (sys_nh_param_misc_t*)(p_para);

    switch (p_para->hdr.change_type)
    {
    case SYS_NH_CHANGE_TYPE_FWD_TO_UNROV:
        break;
    case SYS_NH_CHANGE_TYPE_UNROV_TO_FWD:
        break;
    case SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR:
        CTC_ERROR_RETURN(_sys_usw_nh_update_misc_fwd_attr(lchip, p_nh_para, p_nh_info));
        break;

    case SYS_NH_CHANGE_TYPE_ADD_DYNTBL:
        {
            SYS_NH_DSFWD_CHK(p_nh_info->hdr.nh_entry_flags, p_para->hdr.is_dsfwd1);
            CTC_ERROR_RETURN(_sys_usw_nh_misc_add_dsfwd(lchip, p_nh_db, p_para->hdr.is_dsfwd1));
        }
    	break;
    default:
        return CTC_E_INVALID_PARAM;
    }

    if (p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
    {
        int32 ret = 0;
        ret = (sys_usw_nh_update_ecmp_member(lchip, p_nh_para->hdr.nhid, p_nh_para->hdr.change_type, p_para->hdr.p_nh_info_ext->ecmp_list));
        if (ret)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop update for ecmp fail!, ret:%d \n", ret);
        }
    }
    if (p_nh_para->hdr.p_nh_info_ext && (p_nh_para->hdr.change_type != SYS_NH_CHANGE_TYPE_ADD_DYNTBL))
    {
        sys_nh_ref_list_node_t* p_ref_node = NULL;
        sys_nh_info_com_t* p_nh_com = NULL;

        p_ref_node = p_nh_para->hdr.p_nh_info_ext->aps_list;
        while (p_ref_node)
        {
            p_nh_com = p_ref_node->p_ref_nhinfo;
            sys_usw_nh_update_aps_by_nh(lchip, p_nh_com->hdr.nh_id, p_nh_info->hdr.nh_id);
            p_ref_node = p_ref_node->p_next;
        }
    }
    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOOP_USED))
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_loopback_l2edit(lchip, p_nh_para->hdr.nhid, 1));
    }

    return CTC_E_NONE;
}



int32
sys_usw_nh_misc_init(uint8 lchip)
{
    sys_usw_nh_master_t* p_nh_master = g_usw_nh_master[lchip];
    ctc_spool_t spool;

    sal_memset(&spool, 0, sizeof(ctc_spool_t));

    spool.lchip = lchip;
    spool.block_num = 1;
    spool.block_size = MCHIP_CAP(SYS_CAP_NH_L2EDIT_VLAN_PROFILE_NUM);
    spool.max_count = MCHIP_CAP(SYS_CAP_NH_L2EDIT_VLAN_PROFILE_NUM);
    spool.user_data_size = sizeof(sys_dsl2edit_vlan_edit_t);
    spool.spool_key = (hash_key_fn) _sys_usw_nh_misc_l2edit_make_vlan_edit;
    spool.spool_cmp = (hash_cmp_fn) _sys_usw_nh_misc_l2edit_compare_vlan_edit;
    spool.spool_alloc = (spool_alloc_fn)_sys_usw_nh_misc_vlan_edit_spool_alloc_index;
    spool.spool_free = (spool_free_fn)_sys_usw_nh_misc_vlan_edit_spool_free_index;
    p_nh_master->p_l2edit_vprof = ctc_spool_create(&spool);


  return CTC_E_NONE;
}


